diff options
79 files changed, 1900 insertions, 572 deletions
diff --git a/Help/command/LINK_OPTIONS_LINKER.txt b/Help/command/LINK_OPTIONS_LINKER.txt index a723375..3f66181 100644 --- a/Help/command/LINK_OPTIONS_LINKER.txt +++ b/Help/command/LINK_OPTIONS_LINKER.txt @@ -1,8 +1,8 @@ -To pass options to the linker tool, each compiler driver has is own syntax. -The ``LINKER:`` prefix can be used to specify, in a portable way, options -to pass to the linker tool. The ``LINKER:`` prefix is replaced by the required -driver option and the rest of the option string defines linker arguments using -``,`` as separator. These arguments will be formatted according to the +To pass options to the linker tool, each compiler driver has its own syntax. +The ``LINKER:`` prefix and ``,`` separator can be used to specify, in a portable +way, options to pass to the linker tool. ``LINKER:`` is replaced by the +appropriate driver option and ``,`` by the appropriate driver separator. +The driver prefix and driver separator are given by the values of the :variable:`CMAKE_<LANG>_LINKER_WRAPPER_FLAG` and :variable:`CMAKE_<LANG>_LINKER_WRAPPER_FLAG_SEP` variables. @@ -12,11 +12,11 @@ For example, ``"LINKER:-z,defs"`` becomes ``-Xlinker -z -Xlinker defs`` for The ``LINKER:`` prefix can be specified as part of a ``SHELL:`` prefix expression. -The ``LINKER:`` prefix supports, as alternate syntax, specification of -arguments using ``SHELL:`` prefix and space as separator. Previous example -becomes ``"LINKER:SHELL:-z defs"``. +The ``LINKER:`` prefix supports, as an alternative syntax, specification of +arguments using the ``SHELL:`` prefix and space as separator. The previous +example then becomes ``"LINKER:SHELL:-z defs"``. .. note:: - Specifying ``SHELL:`` prefix elsewhere than at the beginning of the + Specifying the ``SHELL:`` prefix anywhere other than at the beginning of the ``LINKER:`` prefix is not supported. diff --git a/Help/command/OPTIONS_SHELL.txt b/Help/command/OPTIONS_SHELL.txt index 530c012..0f8ec32 100644 --- a/Help/command/OPTIONS_SHELL.txt +++ b/Help/command/OPTIONS_SHELL.txt @@ -1,9 +1,9 @@ The final set of compile or link options used for a target is constructed by accumulating options from the current target and the usage requirements of -it dependencies. The set of options is de-duplicated to avoid repetition. +its dependencies. The set of options is de-duplicated to avoid repetition. While beneficial for individual options, the de-duplication step can break up option groups. For example, ``-D A -D B`` becomes ``-D A B``. One may specify a group of options using shell-like quoting along with a ``SHELL:`` -prefix. The ``SHELL:`` prefix is dropped and the rest of the option string +prefix. The ``SHELL:`` prefix is dropped, and the rest of the option string is parsed using the :command:`separate_arguments` ``UNIX_COMMAND`` mode. For example, ``"SHELL:-D A" "SHELL:-D B"`` becomes ``-D A -D B``. diff --git a/Help/command/target_precompile_headers.rst b/Help/command/target_precompile_headers.rst index 3a32f41..d283948 100644 --- a/Help/command/target_precompile_headers.rst +++ b/Help/command/target_precompile_headers.rst @@ -47,6 +47,9 @@ with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual for available expressions. See the :manual:`cmake-compile-features(7)` manual for information on compile features and a list of supported compilers. +The ``$<COMPILE_LANGUAGE:...>`` generator expression is particularly +useful for specifying a language-specific header to precompile for +only one language (e.g. ``CXX`` and not ``C``). Usage ^^^^^ @@ -56,6 +59,7 @@ Usage target_precompile_headers(<target> PUBLIC project_header.h + "$<$<COMPILE_LANGUAGE:CXX>:cxx_only.h>" PRIVATE [["other_header.h"]] <unordered_map> diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 1369aa3..02e07eb 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -342,6 +342,7 @@ Properties on Targets /prop_tgt/VS_DOTNET_REFERENCES /prop_tgt/VS_DOTNET_REFERENCES_COPY_LOCAL /prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION + /prop_tgt/VS_DOTNET_DOCUMENTATION_FILE /prop_tgt/VS_DPI_AWARE /prop_tgt/VS_GLOBAL_KEYWORD /prop_tgt/VS_GLOBAL_PROJECT_TYPES diff --git a/Help/prop_tgt/VS_DOTNET_DOCUMENTATION_FILE.rst b/Help/prop_tgt/VS_DOTNET_DOCUMENTATION_FILE.rst new file mode 100644 index 0000000..1bc361c --- /dev/null +++ b/Help/prop_tgt/VS_DOTNET_DOCUMENTATION_FILE.rst @@ -0,0 +1,6 @@ +VS_DOTNET_DOCUMENTATION_FILE +---------------------------- + +Visual Studio managed project .NET documentation output + +Sets the target XML documentation file output. diff --git a/Help/release/dev/FindCURL-cmake-package.rst b/Help/release/dev/FindCURL-cmake-package.rst new file mode 100644 index 0000000..67c5bbc --- /dev/null +++ b/Help/release/dev/FindCURL-cmake-package.rst @@ -0,0 +1,7 @@ +FindCURL-cmake-package +---------------------- + +* The :module:`FindCURL` module learned to find CURL using + the ``CURLConfig.cmake`` package configuration file generated by + CURL's cmake buildsystem. It also gained a new ``CURL_NO_CURL_CMAKE`` + option to disable this behavior. diff --git a/Help/release/dev/vs_dotnet_documentation_file.rst b/Help/release/dev/vs_dotnet_documentation_file.rst new file mode 100644 index 0000000..fdffb1c --- /dev/null +++ b/Help/release/dev/vs_dotnet_documentation_file.rst @@ -0,0 +1,6 @@ +vs_dotnet_documentation_file +---------------------------- + +* The :prop_tgt:`VS_DOTNET_DOCUMENTATION_FILE` target property was added + to tell :ref:`Visual Studio Generators` to generate a ``DocumentationFile`` + reference in ``.csproj`` files. diff --git a/Modules/CMakeFindBinUtils.cmake b/Modules/CMakeFindBinUtils.cmake index 3887b2d..69ace5a 100644 --- a/Modules/CMakeFindBinUtils.cmake +++ b/Modules/CMakeFindBinUtils.cmake @@ -167,18 +167,6 @@ else() HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) list(APPEND _CMAKE_TOOL_VARS AR RANLIB STRIP LINKER NM OBJDUMP OBJCOPY READELF DLLTOOL ADDR2LINE) - - - unset(_CMAKE_ADDITIONAL_AR_NAMES) - unset(_CMAKE_ADDITIONAL_RANLIB_NAMES) - unset(_CMAKE_ADDITIONAL_STRIP_NAMES) - unset(_CMAKE_ADDITIONAL_LINKER_NAMES) - unset(_CMAKE_ADDITIONAL_NM_NAMES) - unset(_CMAKE_ADDITIONAL_OBJDUMP_NAMES) - unset(_CMAKE_ADDITIONAL_OBJCOPY_NAMES) - unset(_CMAKE_ADDITIONAL_READELF_NAMES) - unset(_CMAKE_ADDITIONAL_DLLTOOL_NAMES) - unset(_CMAKE_ADDITIONAL_ADDR2LINE_NAMES) endif() if(CMAKE_PLATFORM_HAS_INSTALLNAME) diff --git a/Modules/CMakeGraphVizOptions.cmake b/Modules/CMakeGraphVizOptions.cmake index 1911e73..be4a3be 100644 --- a/Modules/CMakeGraphVizOptions.cmake +++ b/Modules/CMakeGraphVizOptions.cmake @@ -5,119 +5,145 @@ CMakeGraphVizOptions -------------------- -The builtin graphviz support of CMake. +The builtin Graphviz support of CMake. -Variables specific to the graphviz support -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Generating Graphviz files +^^^^^^^^^^^^^^^^^^^^^^^^^ -CMake -can generate `graphviz <http://www.graphviz.org/>`_ files, showing the dependencies between the -targets in a project and also external libraries which are linked -against. When CMake is run with the ``--graphviz=foo.dot`` option, it will -produce: +CMake can generate `Graphviz <https://www.graphviz.org/>`_ files showing the +dependencies between the targets in a project, as well as external libraries +which are linked against. -* a ``foo.dot`` file showing all dependencies in the project -* a ``foo.dot.<target>`` file for each target, file showing on which other targets the respective target depends -* a ``foo.dot.<target>.dependers`` file, showing which other targets depend on the respective target +When running CMake with the ``--graphviz=foo.dot`` option, it produces: -The different dependency types ``PUBLIC``, ``PRIVATE`` and ``INTERFACE`` -are represented as solid, dashed and dotted edges. +* a ``foo.dot`` file, showing all dependencies in the project +* a ``foo.dot.<target>`` file for each target, showing on which other targets + it depends +* a ``foo.dot.<target>.dependers`` file for each target, showing which other + targets depend on it -This can result in huge graphs. Using the file -``CMakeGraphVizOptions.cmake`` the look and content of the generated -graphs can be influenced. This file is searched first in -:variable:`CMAKE_BINARY_DIR` and then in :variable:`CMAKE_SOURCE_DIR`. If found, it is -read and the variables set in it are used to adjust options for the -generated graphviz files. +Those .dot files can be converted to images using the *dot* command from the +Graphviz package: -.. variable:: GRAPHVIZ_GRAPH_TYPE +.. code-block:: shell - The graph type. + dot -Tpng -o foo.png foo.dot - * Mandatory : NO - * Default : "digraph" +The different dependency types ``PUBLIC``, ``INTERFACE`` and ``PRIVATE`` +are represented as solid, dashed and dotted edges. - Valid graph types are: +Variables specific to the Graphviz support +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * "graph" : Nodes are joined with lines - * "digraph" : Nodes are joined with arrows showing direction - * "strict graph" : Like "graph" but max one line between each node - * "strict digraph" : Like "graph" but max one line between each node in each direction +The resulting graphs can be huge. The look and content of the generated graphs +can be controlled using the file ``CMakeGraphVizOptions.cmake``. This file is +first searched in :variable:`CMAKE_BINARY_DIR`, and then in +:variable:`CMAKE_SOURCE_DIR`. If found, the variables set in it are used to +adjust options for the generated Graphviz files. .. variable:: GRAPHVIZ_GRAPH_NAME The graph name. - * Mandatory : NO - * Default : "GG" + * Mandatory: NO + * Default: value of :variable:`CMAKE_PROJECT_NAME` .. variable:: GRAPHVIZ_GRAPH_HEADER - The header written at the top of the graphviz file. + The header written at the top of the Graphviz files. - * Mandatory : NO - * Default : "node [n fontsize = "12"];" + * Mandatory: NO + * Default: "node [ fontsize = "12" ];" .. variable:: GRAPHVIZ_NODE_PREFIX - The prefix for each node in the graphviz file. + The prefix for each node in the Graphviz files. - * Mandatory : NO - * Default : "node" + * Mandatory: NO + * Default: "node" .. variable:: GRAPHVIZ_EXECUTABLES - Set this to FALSE to exclude executables from the generated graphs. + Set to FALSE to exclude executables from the generated graphs. - * Mandatory : NO - * Default : TRUE + * Mandatory: NO + * Default: TRUE .. variable:: GRAPHVIZ_STATIC_LIBS - Set this to FALSE to exclude static libraries from the generated graphs. + Set to FALSE to exclude static libraries from the generated graphs. - * Mandatory : NO - * Default : TRUE + * Mandatory: NO + * Default: TRUE .. variable:: GRAPHVIZ_SHARED_LIBS - Set this to FALSE to exclude shared libraries from the generated graphs. + Set to FALSE to exclude shared libraries from the generated graphs. - * Mandatory : NO - * Default : TRUE + * Mandatory: NO + * Default: TRUE .. variable:: GRAPHVIZ_MODULE_LIBS - Set this to FALSE to exclude module libraries from the generated graphs. + Set to FALSE to exclude module libraries from the generated graphs. + + * Mandatory: NO + * Default: TRUE + +.. variable:: GRAPHVIZ_INTERFACE_LIBS + + Set to FALSE to exclude interface libraries from the generated graphs. + + * Mandatory: NO + * Default: TRUE - * Mandatory : NO - * Default : TRUE +.. variable:: GRAPHVIZ_OBJECT_LIBS + + Set to FALSE to exclude object libraries from the generated graphs. + + * Mandatory: NO + * Default: TRUE + +.. variable:: GRAPHVIZ_UNKNOWN_LIBS + + Set to FALSE to exclude unknown libraries from the generated graphs. + + * Mandatory: NO + * Default: TRUE .. variable:: GRAPHVIZ_EXTERNAL_LIBS - Set this to FALSE to exclude external libraries from the generated graphs. + Set to FALSE to exclude external libraries from the generated graphs. + + * Mandatory: NO + * Default: TRUE + +.. variable:: GRAPHVIZ_CUSTOM_TARGETS + + Set to TRUE to include custom targets in the generated graphs. - * Mandatory : NO - * Default : TRUE + * Mandatory: NO + * Default: FALSE .. variable:: GRAPHVIZ_IGNORE_TARGETS - A list of regular expressions for ignoring targets. + A list of regular expressions for names of targets to exclude from the + generated graphs. - * Mandatory : NO - * Default : empty + * Mandatory: NO + * Default: empty .. variable:: GRAPHVIZ_GENERATE_PER_TARGET - Set this to FALSE to exclude per target graphs ``foo.dot.<target>``. + Set to FALSE to not generate per-target graphs ``foo.dot.<target>``. - * Mandatory : NO - * Default : TRUE + * Mandatory: NO + * Default: TRUE .. variable:: GRAPHVIZ_GENERATE_DEPENDERS - Set this to FALSE to exclude depender graphs ``foo.dot.<target>.dependers``. + Set to FALSE to not generate depender graphs ``foo.dot.<target>.dependers``. - * Mandatory : NO - * Default : TRUE + * Mandatory: NO + * Default: TRUE #]=======================================================================] diff --git a/Modules/FindCURL.cmake b/Modules/FindCURL.cmake index aeebc84..919babc 100644 --- a/Modules/FindCURL.cmake +++ b/Modules/FindCURL.cmake @@ -37,8 +37,35 @@ This module defines the following variables: ``CURL_VERSION_STRING`` The version of ``curl`` found. + +CURL CMake +^^^^^^^^^^ + +If CURL was built using the CMake buildsystem then it provides its own +``CURLConfig.cmake`` file for use with the :command:`find_package` command's +config mode. This module looks for this file and, if found, +returns its results with no further action. + +Set ``CURL_NO_CURL_CMAKE`` to ``ON`` to disable this search. + #]=======================================================================] +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) + +if(NOT CURL_NO_CURL_CMAKE) + # do a find package call to specifically look for the CMake version + # of curl + find_package(CURL QUIET NO_MODULE) + mark_as_advanced(CURL_DIR) + + # if we found the CURL cmake package then we are done, and + # can print what we found and return. + if(CURL_FOUND) + find_package_handle_standard_args(CURL HANDLE_COMPONENTS CONFIG_MODE) + return() + endif() +endif() + find_package(PkgConfig QUIET) if(PKG_CONFIG_FOUND) pkg_check_modules(PC_CURL QUIET libcurl) @@ -139,7 +166,6 @@ if(CURL_FIND_COMPONENTS) endforeach() endif() -include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) find_package_handle_standard_args(CURL REQUIRED_VARS CURL_LIBRARY CURL_INCLUDE_DIR VERSION_VAR CURL_VERSION_STRING diff --git a/Modules/FindCurses.cmake b/Modules/FindCurses.cmake index 5abc08a..ad40522 100644 --- a/Modules/FindCurses.cmake +++ b/Modules/FindCurses.cmake @@ -134,11 +134,13 @@ if(CURSES_USE_NCURSES) endif() if (CURSES_NEED_WIDE) + set(CURSES_TINFO_LIBRARY_NAME tinfow) find_path(CURSES_INCLUDE_PATH NAMES ncursesw/ncurses.h ncursesw/curses.h ncursesw.h cursesw.h HINTS "${_cursesParentDir}/include" ) else() + set(CURSES_TINFO_LIBRARY_NAME tinfo) find_path(CURSES_INCLUDE_PATH NAMES ncurses/ncurses.h ncurses/curses.h ncurses.h curses.h HINTS "${_cursesParentDir}/include" @@ -153,8 +155,8 @@ if(CURSES_USE_NCURSES) CHECK_LIBRARY_EXISTS("${CURSES_NCURSES_LIBRARY}" cbreak "" CURSES_NCURSES_HAS_CBREAK) if(NOT CURSES_NCURSES_HAS_CBREAK) - find_library(CURSES_EXTRA_LIBRARY tinfo HINTS "${_cursesLibDir}") - find_library(CURSES_EXTRA_LIBRARY tinfo ) + find_library(CURSES_EXTRA_LIBRARY "${CURSES_TINFO_LIBRARY_NAME}" HINTS "${_cursesLibDir}") + find_library(CURSES_EXTRA_LIBRARY "${CURSES_TINFO_LIBRARY_NAME}" ) endif() else() get_filename_component(_cursesLibDir "${CURSES_CURSES_LIBRARY}" PATH) diff --git a/Modules/FindHDF5.cmake b/Modules/FindHDF5.cmake index 08863c8..b488418 100644 --- a/Modules/FindHDF5.cmake +++ b/Modules/FindHDF5.cmake @@ -761,7 +761,7 @@ mark_as_advanced( HDF5_DIFF_EXECUTABLE ) if( NOT HDF5_FOUND ) # seed the initial lists of libraries to find with items we know we need set(HDF5_C_LIBRARY_NAMES hdf5) - set(HDF5_C_HL_LIBRARY_NAMES hdf5_hl) + set(HDF5_C_HL_LIBRARY_NAMES hdf5_hl ${HDF5_C_LIBRARY_NAMES} ) set(HDF5_CXX_LIBRARY_NAMES hdf5_cpp ${HDF5_C_LIBRARY_NAMES}) set(HDF5_CXX_HL_LIBRARY_NAMES hdf5_hl_cpp ${HDF5_C_HL_LIBRARY_NAMES} ${HDF5_CXX_LIBRARY_NAMES}) @@ -772,7 +772,7 @@ if( NOT HDF5_FOUND ) foreach(__lang IN LISTS HDF5_LANGUAGE_BINDINGS) # find the HDF5 include directories if("${__lang}" STREQUAL "Fortran") - set(HDF5_INCLUDE_FILENAME hdf5.mod) + set(HDF5_INCLUDE_FILENAME hdf5.mod HDF5.mod) elseif("${__lang}" STREQUAL "CXX") set(HDF5_INCLUDE_FILENAME H5Cpp.h) else() diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index d89a69d..26d2156 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -289,6 +289,8 @@ set(SRCS cmGeneratorExpression.h cmGeneratorTarget.cxx cmGeneratorTarget.h + cmLinkItemGraphVisitor.cxx + cmLinkItemGraphVisitor.h cmGetPipes.cxx cmGetPipes.h cmGlobalCommonGenerator.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 458cc86..beeb0a6 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 16) -set(CMake_VERSION_PATCH 20191015) +set(CMake_VERSION_PATCH 20191018) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 515f446..910cc9d 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -56,6 +56,8 @@ static std::string const kCMAKE_POSITION_INDEPENDENT_CODE = static std::string const kCMAKE_SYSROOT = "CMAKE_SYSROOT"; static std::string const kCMAKE_SYSROOT_COMPILE = "CMAKE_SYSROOT_COMPILE"; static std::string const kCMAKE_SYSROOT_LINK = "CMAKE_SYSROOT_LINK"; +static std::string const kCMAKE_Swift_COMPILER_TARGET = + "CMAKE_Swift_COMPILER_TARGET"; static std::string const kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES = "CMAKE_TRY_COMPILE_OSX_ARCHITECTURES"; static std::string const kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES = @@ -671,6 +673,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, vars.insert(kCMAKE_SYSROOT); vars.insert(kCMAKE_SYSROOT_COMPILE); vars.insert(kCMAKE_SYSROOT_LINK); + vars.insert(kCMAKE_Swift_COMPILER_TARGET); vars.insert(kCMAKE_WARN_DEPRECATED); vars.emplace("CMAKE_MSVC_RUNTIME_LIBRARY"_s); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 3d7eccc..aeef602 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -752,9 +752,9 @@ void cmExportFileGenerator::SetImportLinkInterface( if (iface->ImplementationIsInterface) { // Policy CMP0022 must not be NEW. - this->SetImportLinkProperty(suffix, target, - "IMPORTED_LINK_INTERFACE_LIBRARIES", - iface->Libraries, properties, missingTargets); + this->SetImportLinkProperty( + suffix, target, "IMPORTED_LINK_INTERFACE_LIBRARIES", iface->Libraries, + properties, missingTargets, ImportLinkPropertyTargetNames::Yes); return; } @@ -832,14 +832,14 @@ void cmExportFileGenerator::SetImportDetailProperties( // Add the transitive link dependencies for this configuration. if (cmLinkInterface const* iface = target->GetLinkInterface(config, target)) { - this->SetImportLinkProperty(suffix, target, - "IMPORTED_LINK_INTERFACE_LANGUAGES", - iface->Languages, properties, missingTargets); + this->SetImportLinkProperty( + suffix, target, "IMPORTED_LINK_INTERFACE_LANGUAGES", iface->Languages, + properties, missingTargets, ImportLinkPropertyTargetNames::No); std::vector<std::string> dummy; - this->SetImportLinkProperty(suffix, target, - "IMPORTED_LINK_DEPENDENT_LIBRARIES", - iface->SharedDeps, properties, dummy); + this->SetImportLinkProperty( + suffix, target, "IMPORTED_LINK_DEPENDENT_LIBRARIES", iface->SharedDeps, + properties, dummy, ImportLinkPropertyTargetNames::Yes); if (iface->Multiplicity > 0) { std::string prop = cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix); @@ -880,7 +880,8 @@ template <typename T> void cmExportFileGenerator::SetImportLinkProperty( std::string const& suffix, cmGeneratorTarget* target, const std::string& propName, std::vector<T> const& entries, - ImportPropertyMap& properties, std::vector<std::string>& missingTargets) + ImportPropertyMap& properties, std::vector<std::string>& missingTargets, + ImportLinkPropertyTargetNames targetNames) { // Skip the property if there are no entries. if (entries.empty()) { @@ -895,9 +896,13 @@ void cmExportFileGenerator::SetImportLinkProperty( link_entries += sep; sep = ";"; - std::string temp = asString(l); - this->AddTargetNamespace(temp, target, missingTargets); - link_entries += temp; + if (targetNames == ImportLinkPropertyTargetNames::Yes) { + std::string temp = asString(l); + this->AddTargetNamespace(temp, target, missingTargets); + link_entries += temp; + } else { + link_entries += asString(l); + } } // Store the property. diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index b04a31e..0d69779 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -102,13 +102,19 @@ protected: ImportPropertyMap& properties, std::vector<std::string>& missingTargets); + enum class ImportLinkPropertyTargetNames + { + Yes, + No, + }; template <typename T> void SetImportLinkProperty(std::string const& suffix, cmGeneratorTarget* target, const std::string& propName, std::vector<T> const& entries, ImportPropertyMap& properties, - std::vector<std::string>& missingTargets); + std::vector<std::string>& missingTargets, + ImportLinkPropertyTargetNames targetNames); /** Each subclass knows how to generate its kind of export file. */ virtual bool GenerateMainFile(std::ostream& os) = 0; diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx index e0d545d..7759c5f 100644 --- a/Source/cmGraphVizWriter.cxx +++ b/Source/cmGraphVizWriter.cxx @@ -2,174 +2,190 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGraphVizWriter.h" -#include <cstddef> +#include <cctype> #include <iostream> #include <memory> -#include <sstream> +#include <set> #include <utility> +#include <cm/memory> + #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmLinkItem.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmState.h" #include "cmStateSnapshot.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -#include "cmTarget.h" #include "cmake.h" namespace { -enum LinkLibraryScopeType -{ - LLT_SCOPE_PUBLIC, - LLT_SCOPE_PRIVATE, - LLT_SCOPE_INTERFACE -}; -const char* const GRAPHVIZ_PRIVATE_EDEGE_STYLE = "dashed"; -const char* const GRAPHVIZ_INTERFACE_EDEGE_STYLE = "dotted"; +char const* const GRAPHVIZ_EDGE_STYLE_PUBLIC = "solid"; +char const* const GRAPHVIZ_EDGE_STYLE_INTERFACE = "dashed"; +char const* const GRAPHVIZ_EDGE_STYLE_PRIVATE = "dotted"; -std::string getLinkLibraryStyle(const LinkLibraryScopeType& type) -{ - std::string style; - switch (type) { - case LLT_SCOPE_PRIVATE: - style = "[style = " + std::string(GRAPHVIZ_PRIVATE_EDEGE_STYLE) + "]"; - break; - case LLT_SCOPE_INTERFACE: - style = "[style = " + std::string(GRAPHVIZ_INTERFACE_EDEGE_STYLE) + "]"; - break; - default: - break; - } - return style; -} +char const* const GRAPHVIZ_NODE_SHAPE_EXECUTABLE = "egg"; // egg-xecutable + +// Normal libraries. +char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC = "octagon"; +char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED = "doubleoctagon"; +char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE = "tripleoctagon"; -const char* getShapeForTarget(const cmGeneratorTarget* target) +char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE = "pentagon"; +char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT = "hexagon"; +char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN = "septagon"; + +char const* const GRAPHVIZ_NODE_SHAPE_UTILITY = "box"; + +const char* getShapeForTarget(const cmLinkItem& item) { - if (!target) { - return "ellipse"; + if (item.Target == nullptr) { + return GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN; } - switch (target->GetType()) { + switch (item.Target->GetType()) { case cmStateEnums::EXECUTABLE: - return "house"; + return GRAPHVIZ_NODE_SHAPE_EXECUTABLE; case cmStateEnums::STATIC_LIBRARY: - return "diamond"; + return GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC; case cmStateEnums::SHARED_LIBRARY: - return "polygon"; + return GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED; case cmStateEnums::MODULE_LIBRARY: - return "octagon"; + return GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE; + case cmStateEnums::OBJECT_LIBRARY: + return GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT; + case cmStateEnums::UTILITY: + return GRAPHVIZ_NODE_SHAPE_UTILITY; + case cmStateEnums::INTERFACE_LIBRARY: + return GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE; + case cmStateEnums::UNKNOWN_LIBRARY: default: - break; + return GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN; } +} +} - return "box"; +cmGraphVizWriter::cmGraphVizWriter(std::string const& fileName, + const cmGlobalGenerator* globalGenerator) + : FileName(fileName) + , GlobalFileStream(fileName) + , GraphName(globalGenerator->GetSafeGlobalSetting("CMAKE_PROJECT_NAME")) + , GraphHeader("node [\n fontsize = \"12\"\n];") + , GraphNodePrefix("node") + , GlobalGenerator(globalGenerator) + , NextNodeId(0) + , GenerateForExecutables(true) + , GenerateForStaticLibs(true) + , GenerateForSharedLibs(true) + , GenerateForModuleLibs(true) + , GenerateForInterfaceLibs(true) + , GenerateForObjectLibs(true) + , GenerateForUnknownLibs(true) + , GenerateForCustomTargets(false) + , GenerateForExternals(true) + , GeneratePerTarget(true) + , GenerateDependers(true) +{ } -std::map<std::string, LinkLibraryScopeType> getScopedLinkLibrariesFromTarget( - cmTarget* Target, const cmGlobalGenerator* globalGenerator) +cmGraphVizWriter::~cmGraphVizWriter() { - char sep = ';'; - std::map<std::string, LinkLibraryScopeType> tokens; - size_t start = 0; - size_t end = 0; + this->WriteFooter(this->GlobalFileStream); - const char* pInterfaceLinkLibraries = - Target->GetProperty("INTERFACE_LINK_LIBRARIES"); - const char* pLinkLibraries = Target->GetProperty("LINK_LIBRARIES"); + for (auto& fileStream : this->PerTargetFileStreams) { + this->WriteFooter(*fileStream.second); + } - if (!pInterfaceLinkLibraries && !pLinkLibraries) { - return tokens; // target is not linked against any other libraries + for (auto& fileStream : this->TargetDependersFileStreams) { + this->WriteFooter(*fileStream.second); } +} - // make sure we don't touch a null-ptr - auto interfaceLinkLibraries = - std::string(pInterfaceLinkLibraries ? pInterfaceLinkLibraries : ""); - auto linkLibraries = std::string(pLinkLibraries ? pLinkLibraries : ""); +void cmGraphVizWriter::VisitGraph(std::string const&) +{ + this->WriteHeader(GlobalFileStream, this->GraphName); + this->WriteLegend(GlobalFileStream); +} - // first extract interfaceLinkLibraries - while (start < interfaceLinkLibraries.length()) { +void cmGraphVizWriter::OnItem(cmLinkItem const& item) +{ + if (this->ItemExcluded(item)) { + return; + } - if ((end = interfaceLinkLibraries.find(sep, start)) == std::string::npos) { - end = interfaceLinkLibraries.length(); - } + NodeNames[item.AsStr()] = cmStrCat(GraphNodePrefix, NextNodeId); + ++NextNodeId; - std::string element = interfaceLinkLibraries.substr(start, end - start); - if (globalGenerator->IsAlias(element)) { - const auto tgt = globalGenerator->FindTarget(element); - if (tgt) { - element = tgt->GetName(); - } - } + this->WriteNode(this->GlobalFileStream, item); - if (std::string::npos == element.find("$<LINK_ONLY:", 0)) { - // we assume first, that this library is an interface library. - // if we find it again in the linklibraries property, we promote it to an - // public library. - tokens[element] = LLT_SCOPE_INTERFACE; - } else { - // this is an private linked static library. - // we take care of this case in the second iterator. - } - start = end + 1; + if (this->GeneratePerTarget) { + this->CreateTargetFile(this->PerTargetFileStreams, item); } - // second extract linkLibraries - start = 0; - while (start < linkLibraries.length()) { - - if ((end = linkLibraries.find(sep, start)) == std::string::npos) { - end = linkLibraries.length(); - } + if (this->GenerateDependers) { + this->CreateTargetFile(this->TargetDependersFileStreams, item, + ".dependers"); + } +} - std::string element = linkLibraries.substr(start, end - start); - if (globalGenerator->IsAlias(element)) { - const auto tgt = globalGenerator->FindTarget(element); - if (tgt) { - element = tgt->GetName(); - } - } +void cmGraphVizWriter::CreateTargetFile(FileStreamMap& fileStreamMap, + cmLinkItem const& item, + std::string const& fileNameSuffix) +{ + auto const pathSafeItemName = PathSafeString(item.AsStr()); + auto const perTargetFileName = + cmStrCat(this->FileName, '.', pathSafeItemName, fileNameSuffix); + auto perTargetFileStream = + cm::make_unique<cmGeneratedFileStream>(perTargetFileName); - if (tokens.find(element) == tokens.end()) { - // this library is not found in interfaceLinkLibraries but in - // linkLibraries. - // this results in a private linked library. - tokens[element] = LLT_SCOPE_PRIVATE; - } else if (LLT_SCOPE_INTERFACE == tokens[element]) { - // this library is found in interfaceLinkLibraries and linkLibraries. - // this results in a public linked library. - tokens[element] = LLT_SCOPE_PUBLIC; - } else { - // private and public linked libraries should not be changed anymore. - } + this->WriteHeader(*perTargetFileStream, item.AsStr()); + this->WriteNode(*perTargetFileStream, item); - start = end + 1; - } + fileStreamMap.emplace(item.AsStr(), std::move(perTargetFileStream)); +} - return tokens; +void cmGraphVizWriter::OnDirectLink(cmLinkItem const& depender, + cmLinkItem const& dependee, + DependencyType dt) +{ + this->VisitLink(depender, dependee, true, GetEdgeStyle(dt)); } + +void cmGraphVizWriter::OnIndirectLink(cmLinkItem const& depender, + cmLinkItem const& dependee) +{ + this->VisitLink(depender, dependee, false); } -cmGraphVizWriter::cmGraphVizWriter(const cmGlobalGenerator* globalGenerator) - : GraphType("digraph") - , GraphName("GG") - , GraphHeader("node [\n fontsize = \"12\"\n];") - , GraphNodePrefix("node") - , GlobalGenerator(globalGenerator) - , LocalGenerators(globalGenerator->GetLocalGenerators()) - , GenerateForExecutables(true) - , GenerateForStaticLibs(true) - , GenerateForSharedLibs(true) - , GenerateForModuleLibs(true) - , GenerateForInterface(true) - , GenerateForExternals(true) - , GeneratePerTarget(true) - , GenerateDependers(true) - , HaveTargetsAndLibs(false) +void cmGraphVizWriter::VisitLink(cmLinkItem const& depender, + cmLinkItem const& dependee, bool isDirectLink, + std::string const& scopeType) { + if (this->ItemExcluded(depender) || this->ItemExcluded(dependee)) { + return; + } + + if (!isDirectLink) { + return; + } + + this->WriteConnection(this->GlobalFileStream, depender, dependee, scopeType); + + if (this->GeneratePerTarget) { + auto fileStream = PerTargetFileStreams[depender.AsStr()].get(); + this->WriteNode(*fileStream, dependee); + this->WriteConnection(*fileStream, depender, dependee, scopeType); + } + + if (this->GenerateDependers) { + auto fileStream = TargetDependersFileStreams[dependee.AsStr()].get(); + this->WriteNode(*fileStream, depender); + this->WriteConnection(*fileStream, depender, dependee, scopeType); + } } void cmGraphVizWriter::ReadSettings( @@ -208,7 +224,6 @@ void cmGraphVizWriter::ReadSettings( } \ } while (false) - __set_if_set(this->GraphType, "GRAPHVIZ_GRAPH_TYPE"); __set_if_set(this->GraphName, "GRAPHVIZ_GRAPH_NAME"); __set_if_set(this->GraphHeader, "GRAPHVIZ_GRAPH_HEADER"); __set_if_set(this->GraphNodePrefix, "GRAPHVIZ_NODE_PREFIX"); @@ -225,7 +240,10 @@ void cmGraphVizWriter::ReadSettings( __set_bool_if_set(this->GenerateForStaticLibs, "GRAPHVIZ_STATIC_LIBS"); __set_bool_if_set(this->GenerateForSharedLibs, "GRAPHVIZ_SHARED_LIBS"); __set_bool_if_set(this->GenerateForModuleLibs, "GRAPHVIZ_MODULE_LIBS"); - __set_bool_if_set(this->GenerateForInterface, "GRAPHVIZ_INTERFACE"); + __set_bool_if_set(this->GenerateForInterfaceLibs, "GRAPHVIZ_INTERFACE_LIBS"); + __set_bool_if_set(this->GenerateForObjectLibs, "GRAPHVIZ_OBJECT_LIBS"); + __set_bool_if_set(this->GenerateForUnknownLibs, "GRAPHVIZ_UNKNOWN_LIBS"); + __set_bool_if_set(this->GenerateForCustomTargets, "GRAPHVIZ_CUSTOM_TARGETS"); __set_bool_if_set(this->GenerateForExternals, "GRAPHVIZ_EXTERNAL_LIBS"); __set_bool_if_set(this->GeneratePerTarget, "GRAPHVIZ_GENERATE_PER_TARGET"); __set_bool_if_set(this->GenerateDependers, "GRAPHVIZ_GENERATE_DEPENDERS"); @@ -248,329 +266,170 @@ void cmGraphVizWriter::ReadSettings( } } -// Iterate over all targets and write for each one a graph which shows -// which other targets depend on it. -void cmGraphVizWriter::WriteTargetDependersFiles(const std::string& fileName) +void cmGraphVizWriter::Write() { - if (!this->GenerateDependers) { - return; - } - - this->CollectTargetsAndLibs(); - - for (auto const& ptr : this->TargetPtrs) { - if (ptr.second == nullptr) { - continue; - } - - if (!this->GenerateForTargetType(ptr.second->GetType())) { - continue; - } - - std::string currentFilename = - cmStrCat(fileName, '.', ptr.first, ".dependers"); - - cmGeneratedFileStream str(currentFilename); - if (!str) { - return; + auto gg = this->GlobalGenerator; + + this->VisitGraph(gg->GetName()); + + // We want to traverse in a determined order, such that the output is always + // the same for a given project (this makes tests reproducible, etc.) + std::set<cmGeneratorTarget const*, cmGeneratorTarget::StrictTargetComparison> + sortedGeneratorTargets; + + for (cmLocalGenerator const* lg : gg->GetLocalGenerators()) { + for (cmGeneratorTarget const* gt : lg->GetGeneratorTargets()) { + // Reserved targets have inconsistent names across platforms (e.g. 'all' + // vs. 'ALL_BUILD'), which can disrupt the traversal ordering. + // We don't need or want them anyway. + if (!cmGlobalGenerator::IsReservedTarget(gt->GetName())) { + sortedGeneratorTargets.insert(gt); + } } - - std::set<std::string> insertedConnections; - std::set<std::string> insertedNodes; - - std::cout << "Writing " << currentFilename << "..." << std::endl; - this->WriteHeader(str); - - this->WriteDependerConnections(ptr.first, insertedNodes, - insertedConnections, str); - - this->WriteFooter(str); - } -} - -// Iterate over all targets and write for each one a graph which shows -// on which targets it depends. -void cmGraphVizWriter::WritePerTargetFiles(const std::string& fileName) -{ - if (!this->GeneratePerTarget) { - return; } - this->CollectTargetsAndLibs(); - - for (auto const& ptr : this->TargetPtrs) { - if (ptr.second == nullptr) { - continue; - } - - if (!this->GenerateForTargetType(ptr.second->GetType())) { - continue; - } - - std::set<std::string> insertedConnections; - std::set<std::string> insertedNodes; - - std::string currentFilename = cmStrCat(fileName, '.', ptr.first); - cmGeneratedFileStream str(currentFilename); - if (!str) { - return; - } - - std::cout << "Writing " << currentFilename << "..." << std::endl; - this->WriteHeader(str); - - this->WriteConnections(ptr.first, insertedNodes, insertedConnections, str); - this->WriteFooter(str); + for (auto const gt : sortedGeneratorTargets) { + auto item = cmLinkItem(gt, gt->GetBacktrace()); + this->VisitItem(item); } } -void cmGraphVizWriter::WriteGlobalFile(const std::string& fileName) +void cmGraphVizWriter::WriteHeader(cmGeneratedFileStream& fs, + const std::string& name) { - this->CollectTargetsAndLibs(); - - cmGeneratedFileStream str(fileName); - if (!str) { - return; - } - this->WriteHeader(str); - - std::cout << "Writing " << fileName << "..." << std::endl; - - std::set<std::string> insertedConnections; - std::set<std::string> insertedNodes; - - for (auto const& ptr : this->TargetPtrs) { - if (ptr.second == nullptr) { - continue; - } - - if (!this->GenerateForTargetType(ptr.second->GetType())) { - continue; - } - - this->WriteConnections(ptr.first, insertedNodes, insertedConnections, str); - } - this->WriteFooter(str); + auto const escapedGraphName = EscapeForDotFile(name); + fs << "digraph \"" << escapedGraphName << "\" {" << std::endl; + fs << this->GraphHeader << std::endl; } -void cmGraphVizWriter::WriteHeader(cmGeneratedFileStream& str) const +void cmGraphVizWriter::WriteFooter(cmGeneratedFileStream& fs) { - str << this->GraphType << " \"" << this->GraphName << "\" {" << std::endl; - str << this->GraphHeader << std::endl; + fs << "}" << std::endl; } -void cmGraphVizWriter::WriteFooter(cmGeneratedFileStream& str) const +void cmGraphVizWriter::WriteLegend(cmGeneratedFileStream& fs) { - str << "}" << std::endl; + // Note that the subgraph name must start with "cluster", as done here, to + // make Graphviz layout engines do the right thing and keep the nodes + // together. + fs << "subgraph clusterLegend {" << std::endl; + fs << " label = \"Legend\";" << std::endl; + // Set the color of the box surrounding the legend. + fs << " color = black;" << std::endl; + // We use invisible edges just to enforce the layout. + fs << " edge [ style = invis ];" << std::endl; + + // Nodes. + fs << " legendNode0 [ label = \"Executable\", shape = " + << GRAPHVIZ_NODE_SHAPE_EXECUTABLE << " ];" << std::endl; + + fs << " legendNode1 [ label = \"Static Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC << " ];" << std::endl; + fs << " legendNode2 [ label = \"Shared Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED << " ];" << std::endl; + fs << " legendNode3 [ label = \"Module Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE << " ];" << std::endl; + + fs << " legendNode4 [ label = \"Interface Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE << " ];" << std::endl; + fs << " legendNode5 [ label = \"Object Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT << " ];" << std::endl; + fs << " legendNode6 [ label = \"Unknown Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN << " ];" << std::endl; + + fs << " legendNode7 [ label = \"Custom Target\", shape = " + << GRAPHVIZ_NODE_SHAPE_UTILITY << " ];" << std::endl; + + // Edges. + // Some of those are dummy (invisible) edges to enforce a layout. + fs << " legendNode0 -> legendNode1 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC + << " ];" << std::endl; + fs << " legendNode0 -> legendNode2 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC + << " ];" << std::endl; + fs << " legendNode0 -> legendNode3;" << std::endl; + + fs << " legendNode1 -> legendNode4 [ label = \"Interface\", style = " + << GRAPHVIZ_EDGE_STYLE_INTERFACE << " ];" << std::endl; + fs << " legendNode2 -> legendNode5 [ label = \"Private\", style = " + << GRAPHVIZ_EDGE_STYLE_PRIVATE << " ];" << std::endl; + fs << " legendNode3 -> legendNode6 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC + << " ];" << std::endl; + + fs << " legendNode0 -> legendNode7;" << std::endl; + + fs << "}" << std::endl; } -void cmGraphVizWriter::WriteConnections( - const std::string& targetName, std::set<std::string>& insertedNodes, - std::set<std::string>& insertedConnections, cmGeneratedFileStream& str) const +void cmGraphVizWriter::WriteNode(cmGeneratedFileStream& fs, + cmLinkItem const& item) { - auto targetPtrIt = this->TargetPtrs.find(targetName); + auto const& itemName = item.AsStr(); + auto const& nodeName = this->NodeNames[itemName]; - if (targetPtrIt == this->TargetPtrs.end()) // not found at all - { - return; - } - - this->WriteNode(targetName, targetPtrIt->second, insertedNodes, str); - - if (targetPtrIt->second == nullptr) // it's an external library - { - return; - } + auto const itemNameWithAliases = ItemNameWithAliases(itemName); + auto const escapedLabel = EscapeForDotFile(itemNameWithAliases); - std::string myNodeName = this->TargetNamesNodes.find(targetName)->second; - std::map<std::string, LinkLibraryScopeType> ll = - getScopedLinkLibrariesFromTarget(targetPtrIt->second->Target, - GlobalGenerator); - - for (auto const& llit : ll) { - const std::string& libName = llit.first; - auto libNameIt = this->TargetNamesNodes.find(libName); - - // can happen e.g. if GRAPHVIZ_TARGET_IGNORE_REGEX is used - if (libNameIt == this->TargetNamesNodes.end()) { - continue; - } + fs << " \"" << nodeName << "\" [ label = \"" << escapedLabel + << "\", shape = " << getShapeForTarget(item) << " ];" << std::endl; +} - std::string connectionName = cmStrCat(myNodeName, '-', libNameIt->second); - if (insertedConnections.find(connectionName) == - insertedConnections.end()) { - insertedConnections.insert(connectionName); - this->WriteNode(libName, this->TargetPtrs.find(libName)->second, - insertedNodes, str); +void cmGraphVizWriter::WriteConnection(cmGeneratedFileStream& fs, + cmLinkItem const& depender, + cmLinkItem const& dependee, + std::string const& edgeStyle) +{ + auto const& dependerName = depender.AsStr(); + auto const& dependeeName = dependee.AsStr(); - str << " \"" << myNodeName << "\" -> \"" << libNameIt->second << "\""; + fs << " \"" << this->NodeNames[dependerName] << "\" -> \"" + << this->NodeNames[dependeeName] << "\" "; - str << getLinkLibraryStyle(llit.second); + fs << edgeStyle; - str << " // " << targetName << " -> " << libName << std::endl; - this->WriteConnections(libName, insertedNodes, insertedConnections, str); - } - } + fs << " // " << dependerName << " -> " << dependeeName << std::endl; } -void cmGraphVizWriter::WriteDependerConnections( - const std::string& targetName, std::set<std::string>& insertedNodes, - std::set<std::string>& insertedConnections, cmGeneratedFileStream& str) const +bool cmGraphVizWriter::ItemExcluded(cmLinkItem const& item) { - auto targetPtrIt = this->TargetPtrs.find(targetName); + auto const itemName = item.AsStr(); - if (targetPtrIt == this->TargetPtrs.end()) // not found at all - { - return; + if (this->ItemNameFilteredOut(itemName)) { + return true; } - this->WriteNode(targetName, targetPtrIt->second, insertedNodes, str); - - if (targetPtrIt->second == nullptr) // it's an external library - { - return; + if (item.Target == nullptr) { + return !this->GenerateForExternals; } - std::string myNodeName = this->TargetNamesNodes.find(targetName)->second; - - // now search who links against me - for (auto const& tptr : this->TargetPtrs) { - if (tptr.second == nullptr) { - continue; - } - - if (!this->GenerateForTargetType(tptr.second->GetType())) { - continue; - } - - // Now we have a target, check whether it links against targetName. - // If so, draw a connection, and then continue with dependers on that one. - std::map<std::string, LinkLibraryScopeType> ll = - getScopedLinkLibrariesFromTarget(tptr.second->Target, GlobalGenerator); - - for (auto const& llit : ll) { - if (llit.first == targetName) { - // So this target links against targetName. - auto dependerNodeNameIt = this->TargetNamesNodes.find(tptr.first); - - if (dependerNodeNameIt != this->TargetNamesNodes.end()) { - std::string connectionName = - cmStrCat(dependerNodeNameIt->second, '-', myNodeName); - - if (insertedConnections.find(connectionName) == - insertedConnections.end()) { - insertedConnections.insert(connectionName); - this->WriteNode(tptr.first, tptr.second, insertedNodes, str); - - str << " \"" << dependerNodeNameIt->second << "\" -> \"" - << myNodeName << "\""; - str << " // " << targetName << " -> " << tptr.first << std::endl; - str << getLinkLibraryStyle(llit.second); - this->WriteDependerConnections(tptr.first, insertedNodes, - insertedConnections, str); - } - } - break; - } + if (item.Target->GetType() == cmStateEnums::UTILITY) { + if ((itemName.find("Nightly") == 0) || + (itemName.find("Continuous") == 0) || + (itemName.find("Experimental") == 0)) { + return true; } } -} -void cmGraphVizWriter::WriteNode(const std::string& targetName, - const cmGeneratorTarget* target, - std::set<std::string>& insertedNodes, - cmGeneratedFileStream& str) const -{ - if (insertedNodes.find(targetName) == insertedNodes.end()) { - insertedNodes.insert(targetName); - auto nameIt = this->TargetNamesNodes.find(targetName); - - str << " \"" << nameIt->second << "\" [ label=\"" << targetName - << "\" shape=\"" << getShapeForTarget(target) << "\"];" << std::endl; + if (item.Target->IsImported() && !this->GenerateForExternals) { + return true; } -} -void cmGraphVizWriter::CollectTargetsAndLibs() -{ - if (!this->HaveTargetsAndLibs) { - this->HaveTargetsAndLibs = true; - int cnt = this->CollectAllTargets(); - if (this->GenerateForExternals) { - this->CollectAllExternalLibs(cnt); - } - } + return !this->TargetTypeEnabled(item.Target->GetType()); } -int cmGraphVizWriter::CollectAllTargets() +bool cmGraphVizWriter::ItemNameFilteredOut(std::string const& itemName) { - int cnt = 0; - // First pass get the list of all cmake targets - for (cmLocalGenerator* lg : this->LocalGenerators) { - const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { - const std::string& realTargetName = target->GetName(); - if (this->IgnoreThisTarget(realTargetName)) { - // Skip ignored targets - continue; - } - // std::cout << "Found target: " << tit->first << std::endl; - std::ostringstream ostr; - ostr << this->GraphNodePrefix << cnt++; - this->TargetNamesNodes[realTargetName] = ostr.str(); - this->TargetPtrs[realTargetName] = target; - } + if (itemName == ">") { + // FIXME: why do we even receive such a target here? + return true; } - return cnt; -} - -int cmGraphVizWriter::CollectAllExternalLibs(int cnt) -{ - // Ok, now find all the stuff we link to that is not in cmake - for (cmLocalGenerator* lg : this->LocalGenerators) { - const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { - const std::string& realTargetName = target->GetName(); - if (this->IgnoreThisTarget(realTargetName)) { - // Skip ignored targets - continue; - } - const cmTarget::LinkLibraryVectorType* ll = - &(target->Target->GetOriginalLinkLibraries()); - for (auto const& llit : *ll) { - std::string libName = llit.first; - if (this->IgnoreThisTarget(libName)) { - // Skip ignored targets - continue; - } - - if (GlobalGenerator->IsAlias(libName)) { - const auto tgt = GlobalGenerator->FindTarget(libName); - if (tgt) { - libName = tgt->GetName(); - } - } - - auto tarIt = this->TargetPtrs.find(libName); - if (tarIt == this->TargetPtrs.end()) { - std::ostringstream ostr; - ostr << this->GraphNodePrefix << cnt++; - this->TargetNamesNodes[libName] = ostr.str(); - this->TargetPtrs[libName] = nullptr; - // str << " \"" << ostr << "\" [ label=\"" << libName - // << "\" shape=\"ellipse\"];" << std::endl; - } - } - } + if (cmGlobalGenerator::IsReservedTarget(itemName)) { + return true; } - return cnt; -} -bool cmGraphVizWriter::IgnoreThisTarget(const std::string& name) -{ for (cmsys::RegularExpression& regEx : this->TargetsToIgnoreRegex) { if (regEx.is_valid()) { - if (regEx.find(name)) { + if (regEx.find(itemName)) { return true; } } @@ -579,7 +438,7 @@ bool cmGraphVizWriter::IgnoreThisTarget(const std::string& name) return false; } -bool cmGraphVizWriter::GenerateForTargetType( +bool cmGraphVizWriter::TargetTypeEnabled( cmStateEnums::TargetType targetType) const { switch (targetType) { @@ -592,9 +451,73 @@ bool cmGraphVizWriter::GenerateForTargetType( case cmStateEnums::MODULE_LIBRARY: return this->GenerateForModuleLibs; case cmStateEnums::INTERFACE_LIBRARY: - return this->GenerateForInterface; + return this->GenerateForInterfaceLibs; + case cmStateEnums::OBJECT_LIBRARY: + return this->GenerateForObjectLibs; + case cmStateEnums::UNKNOWN_LIBRARY: + return this->GenerateForUnknownLibs; + case cmStateEnums::UTILITY: + return this->GenerateForCustomTargets; + case cmStateEnums::GLOBAL_TARGET: + // Built-in targets like edit_cache, etc. + // We don't need/want those in the dot file. + return false; default: break; } return false; } + +std::string cmGraphVizWriter::ItemNameWithAliases( + std::string const& itemName) const +{ + auto nameWithAliases = itemName; + + for (auto const& lg : this->GlobalGenerator->GetLocalGenerators()) { + for (auto const& aliasTargets : lg->GetMakefile()->GetAliasTargets()) { + if (aliasTargets.second == itemName) { + nameWithAliases += "\\n(" + aliasTargets.first + ")"; + } + } + } + + return nameWithAliases; +} + +std::string cmGraphVizWriter::GetEdgeStyle(DependencyType dt) +{ + std::string style; + switch (dt) { + case DependencyType::LinkPrivate: + style = "[ style = " + std::string(GRAPHVIZ_EDGE_STYLE_PRIVATE) + " ]"; + break; + case DependencyType::LinkInterface: + style = "[ style = " + std::string(GRAPHVIZ_EDGE_STYLE_INTERFACE) + " ]"; + break; + default: + break; + } + return style; +} + +std::string cmGraphVizWriter::EscapeForDotFile(std::string const& str) +{ + return cmSystemTools::EscapeChars(str.data(), "\""); +} + +std::string cmGraphVizWriter::PathSafeString(std::string const& str) +{ + std::string pathSafeStr; + + // We'll only keep alphanumerical characters, plus the following ones that + // are common, and safe on all platforms: + auto const extra_chars = std::set<char>{ '.', '-', '_' }; + + for (char c : str) { + if (std::isalnum(c) || extra_chars.find(c) != extra_chars.cend()) { + pathSafeStr += c; + } + } + + return pathSafeStr; +} diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h index 9c3051f..578660d 100644 --- a/Source/cmGraphVizWriter.h +++ b/Source/cmGraphVizWriter.h @@ -6,87 +6,106 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <map> -#include <set> +#include <memory> #include <string> #include <vector> #include "cmsys/RegularExpression.hxx" +#include "cmGeneratedFileStream.h" +#include "cmLinkItemGraphVisitor.h" #include "cmStateTypes.h" -class cmGeneratedFileStream; -class cmGeneratorTarget; -class cmLocalGenerator; +class cmLinkItem; class cmGlobalGenerator; /** This class implements writing files for graphviz (dot) for graphs * representing the dependencies between the targets in the project. */ -class cmGraphVizWriter +class cmGraphVizWriter : public cmLinkItemGraphVisitor { public: - cmGraphVizWriter(const cmGlobalGenerator* globalGenerator); + cmGraphVizWriter(std::string const& fileName, + const cmGlobalGenerator* globalGenerator); + ~cmGraphVizWriter() override; + + void VisitGraph(std::string const& name) override; + + void OnItem(cmLinkItem const& item) override; + + void OnDirectLink(cmLinkItem const& depender, cmLinkItem const& dependee, + DependencyType dt) override; + + void OnIndirectLink(cmLinkItem const& depender, + cmLinkItem const& dependee) override; void ReadSettings(const std::string& settingsFileName, const std::string& fallbackSettingsFileName); - void WritePerTargetFiles(const std::string& fileName); - void WriteTargetDependersFiles(const std::string& fileName); + void Write(); + +private: + using FileStreamMap = + std::map<std::string, std::unique_ptr<cmGeneratedFileStream>>; + + void VisitLink(cmLinkItem const& depender, cmLinkItem const& dependee, + bool isDirectLink, std::string const& scopeType = ""); + + void WriteHeader(cmGeneratedFileStream& fs, std::string const& name); - void WriteGlobalFile(const std::string& fileName); + void WriteFooter(cmGeneratedFileStream& fs); -protected: - void CollectTargetsAndLibs(); + void WriteLegend(cmGeneratedFileStream& fs); - int CollectAllTargets(); + void WriteNode(cmGeneratedFileStream& fs, cmLinkItem const& item); - int CollectAllExternalLibs(int cnt); + void CreateTargetFile(FileStreamMap& fileStreamMap, cmLinkItem const& target, + std::string const& fileNameSuffix = ""); - void WriteHeader(cmGeneratedFileStream& str) const; + void WriteConnection(cmGeneratedFileStream& fs, + cmLinkItem const& dependerTargetName, + cmLinkItem const& dependeeTargetName, + std::string const& edgeStyle); - void WriteConnections(const std::string& targetName, - std::set<std::string>& insertedNodes, - std::set<std::string>& insertedConnections, - cmGeneratedFileStream& str) const; + bool ItemExcluded(cmLinkItem const& item); + bool ItemNameFilteredOut(std::string const& itemName); + bool TargetTypeEnabled(cmStateEnums::TargetType targetType) const; - void WriteDependerConnections(const std::string& targetName, - std::set<std::string>& insertedNodes, - std::set<std::string>& insertedConnections, - cmGeneratedFileStream& str) const; + std::string ItemNameWithAliases(std::string const& itemName) const; - void WriteNode(const std::string& targetName, - const cmGeneratorTarget* target, - std::set<std::string>& insertedNodes, - cmGeneratedFileStream& str) const; + static std::string GetEdgeStyle(DependencyType dt); - void WriteFooter(cmGeneratedFileStream& str) const; + static std::string EscapeForDotFile(std::string const& str); - bool IgnoreThisTarget(const std::string& name); + static std::string PathSafeString(std::string const& str); - bool GenerateForTargetType(cmStateEnums::TargetType targetType) const; + std::string FileName; + cmGeneratedFileStream GlobalFileStream; + FileStreamMap PerTargetFileStreams; + FileStreamMap TargetDependersFileStreams; - std::string GraphType; std::string GraphName; std::string GraphHeader; std::string GraphNodePrefix; std::vector<cmsys::RegularExpression> TargetsToIgnoreRegex; - const cmGlobalGenerator* GlobalGenerator; - const std::vector<cmLocalGenerator*>& LocalGenerators; + cmGlobalGenerator const* GlobalGenerator; - std::map<std::string, const cmGeneratorTarget*> TargetPtrs; - // maps from the actual target names to node names in dot: - std::map<std::string, std::string> TargetNamesNodes; + int NextNodeId; + // maps from the actual item names to node names in dot: + std::map<std::string, std::string> NodeNames; bool GenerateForExecutables; bool GenerateForStaticLibs; bool GenerateForSharedLibs; bool GenerateForModuleLibs; - bool GenerateForInterface; + bool GenerateForInterfaceLibs; + bool GenerateForObjectLibs; + bool GenerateForUnknownLibs; + bool GenerateForCustomTargets; bool GenerateForExternals; bool GeneratePerTarget; bool GenerateDependers; - bool HaveTargetsAndLibs; }; #endif diff --git a/Source/cmLinkItemGraphVisitor.cxx b/Source/cmLinkItemGraphVisitor.cxx new file mode 100644 index 0000000..ab2cf9e --- /dev/null +++ b/Source/cmLinkItemGraphVisitor.cxx @@ -0,0 +1,142 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmLinkItemGraphVisitor.h" + +#include <map> +#include <utility> +#include <vector> + +#include "cmGeneratorTarget.h" +#include "cmLinkItem.h" +#include "cmMakefile.h" + +void cmLinkItemGraphVisitor::VisitItem(cmLinkItem const& item) +{ + if (this->ItemVisited(item)) { + return; + } + + this->OnItem(item); + + this->VisitLinks(item, item); +} + +void cmLinkItemGraphVisitor::VisitLinks(cmLinkItem const& item, + cmLinkItem const& rootItem) +{ + if (this->LinkVisited(item, rootItem)) { + return; + } + + if (item.Target == nullptr) { + return; + } + + for (auto const& config : item.Target->Makefile->GetGeneratorConfigs()) { + this->VisitLinks(item, rootItem, config); + } +} + +void cmLinkItemGraphVisitor::VisitLinks(cmLinkItem const& item, + cmLinkItem const& rootItem, + std::string const& config) +{ + auto const& target = *item.Target; + + DependencyMap dependencies; + cmLinkItemGraphVisitor::GetDependencies(target, config, dependencies); + + for (auto const& d : dependencies) { + auto const& dependency = d.second; + auto const& dependencyType = dependency.first; + auto const& dependee = dependency.second; + this->VisitItem(dependee); + + if (this->LinkVisited(item, dependee)) { + continue; + } + + this->OnDirectLink(item, dependee, dependencyType); + + if (rootItem.AsStr() != item.AsStr()) { + this->OnIndirectLink(rootItem, dependee); + } + + // Visit all the direct and indirect links. + this->VisitLinks(dependee, dependee); + this->VisitLinks(dependee, item); + this->VisitLinks(dependee, rootItem); + } +} + +bool cmLinkItemGraphVisitor::ItemVisited(cmLinkItem const& item) +{ + auto& collection = this->VisitedItems; + + bool const visited = collection.find(item.AsStr()) != collection.cend(); + + if (!visited) { + collection.insert(item.AsStr()); + } + + return visited; +} + +bool cmLinkItemGraphVisitor::LinkVisited(cmLinkItem const& depender, + cmLinkItem const& dependee) +{ + auto const link = std::make_pair<>(depender.AsStr(), dependee.AsStr()); + + bool const linkVisited = + this->VisitedLinks.find(link) != this->VisitedLinks.cend(); + + if (!linkVisited) { + this->VisitedLinks.insert(link); + } + + return linkVisited; +} + +void cmLinkItemGraphVisitor::GetDependencies(cmGeneratorTarget const& target, + std::string const& config, + DependencyMap& dependencies) +{ + auto implementationLibraries = target.GetLinkImplementationLibraries(config); + if (implementationLibraries != nullptr) { + for (auto const& lib : implementationLibraries->Libraries) { + auto const& name = lib.AsStr(); + dependencies[name] = Dependency(DependencyType::LinkPrivate, lib); + } + } + + auto interfaceLibraries = + target.GetLinkInterfaceLibraries(config, &target, true); + if (interfaceLibraries != nullptr) { + for (auto const& lib : interfaceLibraries->Libraries) { + auto const& name = lib.AsStr(); + if (dependencies.find(name) != dependencies.cend()) { + dependencies[name] = Dependency(DependencyType::LinkPublic, lib); + } else { + dependencies[name] = Dependency(DependencyType::LinkInterface, lib); + } + } + } + + std::vector<cmGeneratorTarget*> objectLibraries; + target.GetObjectLibrariesCMP0026(objectLibraries); + for (auto const& lib : objectLibraries) { + auto const& name = lib->GetName(); + if (dependencies.find(name) == dependencies.cend()) { + auto objectItem = cmLinkItem(lib, lib->GetBacktrace()); + dependencies[name] = Dependency(DependencyType::Object, objectItem); + } + } + + auto const& utilityItems = target.GetUtilityItems(); + for (auto const& item : utilityItems) { + auto const& name = item.AsStr(); + if (dependencies.find(name) == dependencies.cend()) { + dependencies[name] = Dependency(DependencyType::Utility, item); + } + } +} diff --git a/Source/cmLinkItemGraphVisitor.h b/Source/cmLinkItemGraphVisitor.h new file mode 100644 index 0000000..21dc659 --- /dev/null +++ b/Source/cmLinkItemGraphVisitor.h @@ -0,0 +1,75 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmLinkItemGraphVisitor_h +#define cmLinkItemGraphVisitor_h + +#include <map> +#include <set> +#include <string> +#include <utility> + +#include "cmLinkItem.h" + +class cmGeneratorTarget; + +/** \class cmLinkItemGraphVisitor + * \brief Visits a graph of linked items. + * + * Allows to visit items and dependency links (direct and indirect) between + * those items. + * This abstract class takes care of the graph traversal, making sure that: + * - it terminates even in the presence of cycles; + * - it visits every object once (and only once); + * - it visits the objects in the same order every time. + * + * Children classes only have to implement OnItem() etc. to handle whatever + * logic they care about. + */ +class cmLinkItemGraphVisitor +{ +public: + virtual ~cmLinkItemGraphVisitor() = default; + + virtual void VisitGraph(std::string const& name) = 0; + + void VisitItem(cmLinkItem const& item); + +protected: + enum class DependencyType + { + LinkInterface, + LinkPublic, + LinkPrivate, + Object, + Utility + }; + + virtual void OnItem(cmLinkItem const& item) = 0; + + virtual void OnDirectLink(cmLinkItem const& depender, + cmLinkItem const& dependee, DependencyType dt) = 0; + + virtual void OnIndirectLink(cmLinkItem const& depender, + cmLinkItem const& dependee) = 0; + +private: + std::set<std::string> VisitedItems; + + std::set<std::pair<std::string, std::string>> VisitedLinks; + + void VisitLinks(cmLinkItem const& item, cmLinkItem const& rootItem); + void VisitLinks(cmLinkItem const& item, cmLinkItem const& rootItem, + std::string const& config); + + using Dependency = std::pair<DependencyType, cmLinkItem>; + using DependencyMap = std::map<std::string, Dependency>; + + bool ItemVisited(cmLinkItem const& item); + bool LinkVisited(cmLinkItem const& depender, cmLinkItem const& dependee); + + static void GetDependencies(cmGeneratorTarget const& target, + std::string const& config, + DependencyMap& dependencies); +}; + +#endif diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 51804d2..767f4e0 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -423,25 +423,17 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( // Create the directory containing the object file. This may be a // subdirectory under the target's directory. - std::string dir = cmSystemTools::GetFilenamePath(obj); - cmSystemTools::MakeDirectory(this->LocalGenerator->ConvertToFullPath(dir)); + { + std::string dir = cmSystemTools::GetFilenamePath(obj); + cmSystemTools::MakeDirectory(this->LocalGenerator->ConvertToFullPath(dir)); + } // Save this in the target's list of object files. this->Objects.push_back(obj); this->CleanFiles.insert(obj); - // TODO: Remove - // std::string relativeObj - //= this->LocalGenerator->GetHomeRelativeOutputPath(); - // relativeObj += obj; - - // we compute some depends when writing the depend.make that we will also - // use in the build.make, same with depMakeFile std::vector<std::string> depends; - // generate the build rule file - this->WriteObjectBuildFile(obj, lang, source, depends); - // The object file should be checked for dependency integrity. std::string objFullPath = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/', obj); @@ -450,12 +442,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( cmSystemTools::CollapseFullPath(source.GetFullPath()); this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, lang, objFullPath, srcFullPath); -} -void cmMakefileTargetGenerator::WriteObjectBuildFile( - std::string& obj, const std::string& lang, cmSourceFile const& source, - std::vector<std::string>& depends) -{ this->LocalGenerator->AppendRuleDepend(depends, this->FlagFileNameFull.c_str()); this->LocalGenerator->AppendRuleDepends(depends, @@ -471,10 +458,14 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( const std::string pchSource = this->GeneratorTarget->GetPchSource(config, lang); if (!pchSource.empty() && !source.GetProperty("SKIP_PRECOMPILE_HEADERS")) { - depends.push_back(this->GeneratorTarget->GetPchHeader(config, lang)); + std::string const& pchHeader = + this->GeneratorTarget->GetPchHeader(config, lang); + depends.push_back(pchHeader); if (source.GetFullPath() != pchSource) { depends.push_back(this->GeneratorTarget->GetPchFile(config, lang)); } + this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, lang, + objFullPath, pchHeader); } std::string relativeObj = diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index f464128..7b9c7a5 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -91,11 +91,6 @@ protected: // write the rules for an object void WriteObjectRuleFiles(cmSourceFile const& source); - // write the build rule for an object - void WriteObjectBuildFile(std::string& obj, const std::string& lang, - cmSourceFile const& source, - std::vector<std::string>& depends); - // write the depend.make file for an object void WriteObjectDependRules(cmSourceFile const& source, std::vector<std::string>& depends); diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 40a0e06..dac86a1 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -681,6 +681,8 @@ void cmVisualStudio10TargetGenerator::Generate() this->WritePlatformExtensions(e1); } + + this->WriteDotNetDocumentationFile(e0); Elem(e0, "PropertyGroup").Attribute("Label", "UserMacros"); this->WriteWinRTPackageCertificateKeyFile(e0); this->WritePathAndIncrementalLinkOptions(e0); @@ -915,6 +917,18 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferenceCustomTags( } } +void cmVisualStudio10TargetGenerator::WriteDotNetDocumentationFile(Elem& e0) +{ + std::string const documentationFile = + this->GeneratorTarget->GetSafeProperty("VS_DOTNET_DOCUMENTATION_FILE"); + + if (this->ProjectType == csproj && !documentationFile.empty()) { + Elem e1(e0, "PropertyGroup"); + Elem e2(e1, "DocumentationFile"); + e2.Content(documentationFile); + } +} + void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0) { std::vector<cmSourceFile const*> resxObjs; diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index a18a33d..0835cde 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -79,6 +79,7 @@ private: void WriteDotNetReference(Elem& e1, std::string const& ref, std::string const& hint, std::string const& config); + void WriteDotNetDocumentationFile(Elem& e0); void WriteImports(Elem& e0); void WriteDotNetReferenceCustomTags(Elem& e2, std::string const& ref); void WriteEmbeddedResourceGroup(Elem& e0); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 47cc59d..4a6108d 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -2291,7 +2291,7 @@ void cmake::MarkCliAsUsed(const std::string& variable) void cmake::GenerateGraphViz(const std::string& fileName) const { #ifndef CMAKE_BOOTSTRAP - cmGraphVizWriter gvWriter(this->GetGlobalGenerator()); + cmGraphVizWriter gvWriter(fileName, this->GetGlobalGenerator()); std::string settingsFile = cmStrCat(this->GetHomeOutputDirectory(), "/CMakeGraphVizOptions.cmake"); @@ -2299,9 +2299,8 @@ void cmake::GenerateGraphViz(const std::string& fileName) const cmStrCat(this->GetHomeDirectory(), "/CMakeGraphVizOptions.cmake"); gvWriter.ReadSettings(settingsFile, fallbackSettingsFile); - gvWriter.WritePerTargetFiles(fileName); - gvWriter.WriteTargetDependersFiles(fileName); - gvWriter.WriteGlobalFile(fileName); + + gvWriter.Write(); #endif } diff --git a/Tests/BuildDepends/CMakeLists.txt b/Tests/BuildDepends/CMakeLists.txt index 39a5131..c1ad17c 100644 --- a/Tests/BuildDepends/CMakeLists.txt +++ b/Tests/BuildDepends/CMakeLists.txt @@ -62,6 +62,12 @@ file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_macro_dir.hxx "static const char* zot_macro_dir = \"zot_macro_dir\";\n") file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_macro_tgt.hxx "static const char* zot_macro_tgt = \"zot_macro_tgt\";\n") +file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_pch.hxx + "#ifndef ZOT_PCH_HXX\n" + "#define ZOT_PCH_HXX\n" + "static const char* zot_pch = \"zot_pch\";\n" + "#endif\n" + ) file(WRITE ${BuildDepends_BINARY_DIR}/Project/link_depends_no_shared_lib.h "#define link_depends_no_shared_lib_value 1\n") @@ -155,7 +161,7 @@ execute_process(COMMAND ${zot} OUTPUT_VARIABLE out RESULT_VARIABLE runResult) string(REGEX REPLACE "[\r\n]" " " out "${out}") message("Run result: ${runResult} Output: \"${out}\"") -set(VALUE_UNCHANGED "[zot] [zot_custom] [zot_macro_dir] [zot_macro_tgt] ") +set(VALUE_UNCHANGED "[zot] [zot_custom] [zot_macro_dir] [zot_macro_tgt] [zot_pch] ") if("${out}" STREQUAL "${VALUE_UNCHANGED}") message("Worked!") else() @@ -245,6 +251,12 @@ file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_macro_dir.hxx "static const char* zot_macro_dir = \"zot_macro_dir changed\";\n") file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_macro_tgt.hxx "static const char* zot_macro_tgt = \"zot_macro_tgt changed\";\n") +file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_pch.hxx + "#ifndef ZOT_PCH_HXX\n" + "#define ZOT_PCH_HXX\n" + "static const char* zot_pch = \"zot_pch changed\";\n" + "#endif\n" + ) file(WRITE ${BuildDepends_BINARY_DIR}/Project/link_depends_no_shared_lib.h "#define link_depends_no_shared_lib_value 0\n") @@ -326,7 +338,7 @@ string(REGEX REPLACE "[\r\n]" " " out "${out}") message("Run result: ${runResult} Output: \"${out}\"") set(VALUE_CHANGED - "[zot changed] [zot_custom changed] [zot_macro_dir changed] [zot_macro_tgt changed] " + "[zot changed] [zot_custom changed] [zot_macro_dir changed] [zot_macro_tgt changed] [zot_pch changed] " ) if("${out}" STREQUAL "${VALUE_CHANGED}") message("Worked!") diff --git a/Tests/BuildDepends/Project/CMakeLists.txt b/Tests/BuildDepends/Project/CMakeLists.txt index 3f41b26..8338800 100644 --- a/Tests/BuildDepends/Project/CMakeLists.txt +++ b/Tests/BuildDepends/Project/CMakeLists.txt @@ -93,6 +93,12 @@ add_executable(zot zot.cxx ${CMAKE_CURRENT_BINARY_DIR}/zot.hxx zot_macro_dir.cxx zot_macro_tgt.cxx) add_dependencies(zot zot_custom) +add_library(zot_pch zot_pch.cxx) +target_link_libraries(zot zot_pch) +if(NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;$]") + target_precompile_headers(zot_pch PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/zot_pch.hxx) +endif() + # Test the #include line macro transformation rule support. set_property( TARGET zot diff --git a/Tests/BuildDepends/Project/zot.cxx b/Tests/BuildDepends/Project/zot.cxx index faee7d3..2d08c4b 100644 --- a/Tests/BuildDepends/Project/zot.cxx +++ b/Tests/BuildDepends/Project/zot.cxx @@ -4,11 +4,12 @@ const char* zot_macro_dir_f(); const char* zot_macro_tgt_f(); +const char* zot_pch_f(); int main() { - printf("[%s] [%s] [%s] [%s]\n", zot, zot_custom, zot_macro_dir_f(), - zot_macro_tgt_f()); + printf("[%s] [%s] [%s] [%s] [%s]\n", zot, zot_custom, zot_macro_dir_f(), + zot_macro_tgt_f(), zot_pch_f()); fflush(stdout); return 0; } diff --git a/Tests/BuildDepends/Project/zot_pch.cxx b/Tests/BuildDepends/Project/zot_pch.cxx new file mode 100644 index 0000000..d9d04c7 --- /dev/null +++ b/Tests/BuildDepends/Project/zot_pch.cxx @@ -0,0 +1,6 @@ +#include <zot_pch.hxx> + +const char* zot_pch_f() +{ + return zot_pch; +} diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index 5cf04e8..9d8a248 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -645,3 +645,8 @@ if(CMAKE_GENERATOR MATCHES "Make|Ninja") EXPORT RequiredExp DESTINATION lib) export(TARGETS testLinkDepends NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake) endif() + +# Test the presence of targets named the same as languages. +# IMPORTED_LINK_INTERFACE_LANGUAGES entries should not be targets. +add_library(C INTERFACE) +add_library(CXX INTERFACE) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 0925c0e..31b280b 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -189,6 +189,7 @@ add_RunCMake_test(GeneratorToolset) add_RunCMake_test(GetPrerequisites) add_RunCMake_test(GNUInstallDirs -DSYSTEM_NAME=${CMAKE_SYSTEM_NAME}) add_RunCMake_test(GoogleTest) # Note: does not actually depend on Google Test +add_RunCMake_test(Graphviz) add_RunCMake_test(TargetPropertyGeneratorExpressions) add_RunCMake_test(Languages) add_RunCMake_test(LinkStatic) diff --git a/Tests/RunCMake/Graphviz/CMakeGraphVizOptions.cmake.in b/Tests/RunCMake/Graphviz/CMakeGraphVizOptions.cmake.in new file mode 100644 index 0000000..8a1c3d0 --- /dev/null +++ b/Tests/RunCMake/Graphviz/CMakeGraphVizOptions.cmake.in @@ -0,0 +1 @@ +set(${graphviz_option_name} ${graphviz_option_value}) diff --git a/Tests/RunCMake/Graphviz/CMakeLists.txt b/Tests/RunCMake/Graphviz/CMakeLists.txt new file mode 100644 index 0000000..d23d4cf --- /dev/null +++ b/Tests/RunCMake/Graphviz/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.15) +project(${RunCMake_TEST} C) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/Graphviz/GraphvizTestProject.cmake b/Tests/RunCMake/Graphviz/GraphvizTestProject.cmake new file mode 100644 index 0000000..772f312 --- /dev/null +++ b/Tests/RunCMake/Graphviz/GraphvizTestProject.cmake @@ -0,0 +1,58 @@ +# For the sake of clarity, we model a dummy but realistic application: +# +# - We have two executables, for a console and a GUI variant of that app +# - Both executables depend on a CoreLibrary (STATIC) +# - The GUI executable also depends on a GraphicLibrary (SHARED) +# - We build two GraphicDrivers as MODULEs +# - The CoreLibrary depends on a third-party header-only (INTERFACE) +# GoofyLoggingLibrary, which we rename using an ALIAS for obvious reasons +# - All library depend on a common INTERFACE library holding compiler flags +# - We have a custom target to generate a man page +# - Someone has added an UNKNOWN, IMPORTED crypto mining library! + +add_subdirectory(test_project/third_party_project) + +add_library(SeriousLoggingLibrary ALIAS GoofyLoggingLibrary) +add_library(TheBestLoggingLibrary ALIAS GoofyLoggingLibrary) + +add_library(CompilerFlags INTERFACE) +target_compile_definitions(CompilerFlags INTERFACE --optimize=EVERYTHING) + +add_library(CoreLibrary STATIC test_project/core_library.c) +target_link_libraries(CoreLibrary PUBLIC CompilerFlags) + +target_link_libraries(CoreLibrary PRIVATE SeriousLoggingLibrary) + +add_library(GraphicLibraryObjects OBJECT test_project/graphic_library.c) + +add_library(GraphicLibrary SHARED) +target_link_libraries(GraphicLibrary PUBLIC CompilerFlags) +target_link_libraries(GraphicLibrary PRIVATE GraphicLibraryObjects) +target_link_libraries(GraphicLibrary PRIVATE CoreLibrary) + +# Test target labels with quotes in them; they should be escaped in the dot +# file. +# See https://gitlab.kitware.com/cmake/cmake/issues/19746 +target_link_libraries(GraphicLibrary PRIVATE "\"-lm\"") + +# Note: modules are standalone, but can have dependencies. +add_library(GraphicDriverOpenGL MODULE test_project/module.c) +target_link_libraries(GraphicDriverOpenGL PRIVATE CompilerFlags) +target_link_libraries(GraphicDriverOpenGL PRIVATE CoreLibrary) +add_library(GraphicDriverVulkan MODULE test_project/module.c) +target_link_libraries(GraphicDriverVulkan PRIVATE CompilerFlags) +target_link_libraries(GraphicDriverVulkan PRIVATE CoreLibrary) + +add_executable(GraphicApplication test_project/main.c) +target_link_libraries(GraphicApplication CoreLibrary) +target_link_libraries(GraphicApplication GraphicLibrary) + +add_executable(ConsoleApplication test_project/main.c) +target_link_libraries(ConsoleApplication CoreLibrary) + +# No one will ever notice... +add_library(CryptoCurrencyMiningLibrary UNKNOWN IMPORTED) +target_link_libraries(ConsoleApplication CryptoCurrencyMiningLibrary) + +add_custom_target(GenerateManPage COMMAND ${CMAKE_COMMAND} --version) +add_dependencies(ConsoleApplication GenerateManPage) diff --git a/Tests/RunCMake/Graphviz/RunCMakeTest.cmake b/Tests/RunCMake/Graphviz/RunCMakeTest.cmake new file mode 100644 index 0000000..c0cea10 --- /dev/null +++ b/Tests/RunCMake/Graphviz/RunCMakeTest.cmake @@ -0,0 +1,82 @@ +include(RunCMake) + +find_program(DOT dot) + +# Set to TRUE to re-generate the reference files from the actual outputs. +# Make sure you verify them! +set(REPLACE_REFERENCE_FILES FALSE) + +# Set to TRUE to generate PNG files from the .dot files, using Graphviz (dot). +# Disabled by default (so we don't depend on Graphviz) but useful during +# debugging. +set(GENERATE_PNG_FILES FALSE) + +# 1. Generate the Graphviz (.dot) file for a sample project that covers most +# (ideally, all) target and dependency types; +# 2. Compare that generated file with a reference file. +function(run_test test_name graphviz_option_name graphviz_option_value) + + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test_name}) + set(RunCMake_TEST_NO_CLEAN 1) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + + # Set ${graphviz_option_name} to ${graphviz_option_value}. + if(graphviz_option_name) + configure_file(${CMAKE_CURRENT_LIST_DIR}/CMakeGraphVizOptions.cmake.in + ${RunCMake_TEST_BINARY_DIR}/CMakeGraphVizOptions.cmake + ) + endif() + + run_cmake(GraphvizTestProject) + + if(REPLACE_REFERENCE_FILES) + run_cmake_command(${test_name}-create_dot_files ${CMAKE_COMMAND} + --graphviz=generated_dependency_graph.dot . + ) + + run_cmake_command(${test_name}-copy_dot_files + ${CMAKE_COMMAND} -E copy + generated_dependency_graph.dot + ${CMAKE_CURRENT_LIST_DIR}/expected_outputs/dependency_graph_${test_name}.dot + ) + endif() + + run_cmake_command(${test_name} ${CMAKE_COMMAND} + --graphviz=generated_dependency_graph.dot . + ) + + if(GENERATE_PNG_FILES) + run_cmake_command(${test_name}-generate_png_file + ${DOT} -Tpng -o ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.png + ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot + ) + endif() + +endfunction() + +run_test(default_options "" "") + +run_test(set_graph_name GRAPHVIZ_GRAPH_NAME "\"CMake Project Dependencies\"") +run_test(set_graph_header GRAPHVIZ_GRAPH_HEADER + "\"node [\n fontsize = \\\"16\\\"\n];\"") +run_test(set_node_prefix GRAPHVIZ_NODE_PREFIX "point") + +run_test(no_executables GRAPHVIZ_EXECUTABLES FALSE) + +run_test(no_static_libs GRAPHVIZ_STATIC_LIBS FALSE) +run_test(no_shared_libs GRAPHVIZ_SHARED_LIBS FALSE) +run_test(no_module_libs GRAPHVIZ_MODULE_LIBS FALSE) + +run_test(no_interface_libs GRAPHVIZ_INTERFACE_LIBS FALSE) +run_test(no_object_libs GRAPHVIZ_OBJECT_LIBS FALSE) +run_test(no_unknown_libs GRAPHVIZ_UNKNOWN_LIBS FALSE) + +run_test(no_external_libs GRAPHVIZ_EXTERNAL_LIBS FALSE) + +run_test(custom_targets GRAPHVIZ_CUSTOM_TARGETS TRUE) + +run_test(no_graphic_libs GRAPHVIZ_IGNORE_TARGETS "Graphic") + +run_test(no_per_target_files GRAPHVIZ_GENERATE_PER_TARGET FALSE) +run_test(no_dependers_files GRAPHVIZ_GENERATE_DEPENDERS FALSE) diff --git a/Tests/RunCMake/Graphviz/default_options-check.cmake b/Tests/RunCMake/Graphviz/default_options-check.cmake new file mode 100644 index 0000000..c9a7562 --- /dev/null +++ b/Tests/RunCMake/Graphviz/default_options-check.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +ensure_files_match( + ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_default_options.dot + ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot) diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_custom_targets.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_custom_targets.dot new file mode 100644 index 0000000..8b0365a --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_custom_targets.dot @@ -0,0 +1,52 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "CompilerFlags", shape = pentagon ]; + "node1" [ label = "ConsoleApplication", shape = egg ]; + "node2" [ label = "CoreLibrary", shape = octagon ]; + "node2" -> "node0" // CoreLibrary -> CompilerFlags + "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary + "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary + "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ]; + "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary + "node5" [ label = "GenerateManPage", shape = box ]; + "node1" -> "node5" // ConsoleApplication -> GenerateManPage + "node6" [ label = "GraphicApplication", shape = egg ]; + "node6" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary + "node7" [ label = "GraphicLibrary", shape = doubleoctagon ]; + "node8" [ label = "\"-lm\"", shape = septagon ]; + "node7" -> "node8" [ style = dotted ] // GraphicLibrary -> "-lm" + "node7" -> "node0" // GraphicLibrary -> CompilerFlags + "node7" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary + "node9" [ label = "GraphicLibraryObjects", shape = hexagon ]; + "node7" -> "node9" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects + "node6" -> "node7" [ style = dotted ] // GraphicApplication -> GraphicLibrary + "node10" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ]; + "node10" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags + "node10" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary + "node11" [ label = "GraphicDriverVulkan", shape = tripleoctagon ]; + "node11" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags + "node11" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_default_options.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_default_options.dot new file mode 100644 index 0000000..1bbf25a --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_default_options.dot @@ -0,0 +1,50 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "CompilerFlags", shape = pentagon ]; + "node1" [ label = "ConsoleApplication", shape = egg ]; + "node2" [ label = "CoreLibrary", shape = octagon ]; + "node2" -> "node0" // CoreLibrary -> CompilerFlags + "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary + "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary + "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ]; + "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary + "node5" [ label = "GraphicApplication", shape = egg ]; + "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary + "node6" [ label = "GraphicLibrary", shape = doubleoctagon ]; + "node7" [ label = "\"-lm\"", shape = septagon ]; + "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm" + "node6" -> "node0" // GraphicLibrary -> CompilerFlags + "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary + "node8" [ label = "GraphicLibraryObjects", shape = hexagon ]; + "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects + "node5" -> "node6" [ style = dotted ] // GraphicApplication -> GraphicLibrary + "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ]; + "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags + "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary + "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ]; + "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags + "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_dependers_files.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_dependers_files.dot new file mode 100644 index 0000000..1bbf25a --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_dependers_files.dot @@ -0,0 +1,50 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "CompilerFlags", shape = pentagon ]; + "node1" [ label = "ConsoleApplication", shape = egg ]; + "node2" [ label = "CoreLibrary", shape = octagon ]; + "node2" -> "node0" // CoreLibrary -> CompilerFlags + "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary + "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary + "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ]; + "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary + "node5" [ label = "GraphicApplication", shape = egg ]; + "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary + "node6" [ label = "GraphicLibrary", shape = doubleoctagon ]; + "node7" [ label = "\"-lm\"", shape = septagon ]; + "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm" + "node6" -> "node0" // GraphicLibrary -> CompilerFlags + "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary + "node8" [ label = "GraphicLibraryObjects", shape = hexagon ]; + "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects + "node5" -> "node6" [ style = dotted ] // GraphicApplication -> GraphicLibrary + "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ]; + "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags + "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary + "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ]; + "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags + "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_executables.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_executables.dot new file mode 100644 index 0000000..558a470 --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_executables.dot @@ -0,0 +1,44 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "CompilerFlags", shape = pentagon ]; + "node1" [ label = "CoreLibrary", shape = octagon ]; + "node1" -> "node0" // CoreLibrary -> CompilerFlags + "node2" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "node1" -> "node2" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary + "node3" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ]; + "node4" [ label = "GraphicLibrary", shape = doubleoctagon ]; + "node5" [ label = "\"-lm\"", shape = septagon ]; + "node4" -> "node5" [ style = dotted ] // GraphicLibrary -> "-lm" + "node4" -> "node0" // GraphicLibrary -> CompilerFlags + "node4" -> "node1" [ style = dotted ] // GraphicLibrary -> CoreLibrary + "node6" [ label = "GraphicLibraryObjects", shape = hexagon ]; + "node4" -> "node6" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects + "node7" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ]; + "node7" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags + "node7" -> "node1" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary + "node8" [ label = "GraphicDriverVulkan", shape = tripleoctagon ]; + "node8" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags + "node8" -> "node1" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_external_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_external_libs.dot new file mode 100644 index 0000000..660af37 --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_external_libs.dot @@ -0,0 +1,46 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "CompilerFlags", shape = pentagon ]; + "node1" [ label = "ConsoleApplication", shape = egg ]; + "node2" [ label = "CoreLibrary", shape = octagon ]; + "node2" -> "node0" // CoreLibrary -> CompilerFlags + "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary + "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary + "node4" [ label = "GraphicApplication", shape = egg ]; + "node4" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary + "node5" [ label = "GraphicLibrary", shape = doubleoctagon ]; + "node5" -> "node0" // GraphicLibrary -> CompilerFlags + "node5" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary + "node6" [ label = "GraphicLibraryObjects", shape = hexagon ]; + "node5" -> "node6" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects + "node4" -> "node5" [ style = dotted ] // GraphicApplication -> GraphicLibrary + "node7" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ]; + "node7" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags + "node7" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary + "node8" [ label = "GraphicDriverVulkan", shape = tripleoctagon ]; + "node8" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags + "node8" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_graphic_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_graphic_libs.dot new file mode 100644 index 0000000..5af7fec --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_graphic_libs.dot @@ -0,0 +1,35 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "CompilerFlags", shape = pentagon ]; + "node1" [ label = "ConsoleApplication", shape = egg ]; + "node2" [ label = "CoreLibrary", shape = octagon ]; + "node2" -> "node0" // CoreLibrary -> CompilerFlags + "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary + "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary + "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ]; + "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary + "node5" [ label = "\"-lm\"", shape = septagon ]; +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_interface_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_interface_libs.dot new file mode 100644 index 0000000..94ec41c --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_interface_libs.dot @@ -0,0 +1,43 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "ConsoleApplication", shape = egg ]; + "node1" [ label = "CoreLibrary", shape = octagon ]; + "node0" -> "node1" [ style = dotted ] // ConsoleApplication -> CoreLibrary + "node2" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ]; + "node0" -> "node2" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary + "node3" [ label = "GraphicApplication", shape = egg ]; + "node3" -> "node1" [ style = dotted ] // GraphicApplication -> CoreLibrary + "node4" [ label = "GraphicLibrary", shape = doubleoctagon ]; + "node5" [ label = "\"-lm\"", shape = septagon ]; + "node4" -> "node5" [ style = dotted ] // GraphicLibrary -> "-lm" + "node4" -> "node1" [ style = dotted ] // GraphicLibrary -> CoreLibrary + "node6" [ label = "GraphicLibraryObjects", shape = hexagon ]; + "node4" -> "node6" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects + "node3" -> "node4" [ style = dotted ] // GraphicApplication -> GraphicLibrary + "node7" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ]; + "node7" -> "node1" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary + "node8" [ label = "GraphicDriverVulkan", shape = tripleoctagon ]; + "node8" -> "node1" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_module_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_module_libs.dot new file mode 100644 index 0000000..65b7a71 --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_module_libs.dot @@ -0,0 +1,44 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "CompilerFlags", shape = pentagon ]; + "node1" [ label = "ConsoleApplication", shape = egg ]; + "node2" [ label = "CoreLibrary", shape = octagon ]; + "node2" -> "node0" // CoreLibrary -> CompilerFlags + "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary + "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary + "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ]; + "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary + "node5" [ label = "GraphicApplication", shape = egg ]; + "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary + "node6" [ label = "GraphicLibrary", shape = doubleoctagon ]; + "node7" [ label = "\"-lm\"", shape = septagon ]; + "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm" + "node6" -> "node0" // GraphicLibrary -> CompilerFlags + "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary + "node8" [ label = "GraphicLibraryObjects", shape = hexagon ]; + "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects + "node5" -> "node6" [ style = dotted ] // GraphicApplication -> GraphicLibrary +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_object_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_object_libs.dot new file mode 100644 index 0000000..8116bc9 --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_object_libs.dot @@ -0,0 +1,48 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "CompilerFlags", shape = pentagon ]; + "node1" [ label = "ConsoleApplication", shape = egg ]; + "node2" [ label = "CoreLibrary", shape = octagon ]; + "node2" -> "node0" // CoreLibrary -> CompilerFlags + "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary + "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary + "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ]; + "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary + "node5" [ label = "GraphicApplication", shape = egg ]; + "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary + "node6" [ label = "GraphicLibrary", shape = doubleoctagon ]; + "node7" [ label = "\"-lm\"", shape = septagon ]; + "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm" + "node6" -> "node0" // GraphicLibrary -> CompilerFlags + "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary + "node5" -> "node6" [ style = dotted ] // GraphicApplication -> GraphicLibrary + "node8" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ]; + "node8" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags + "node8" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary + "node9" [ label = "GraphicDriverVulkan", shape = tripleoctagon ]; + "node9" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags + "node9" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_per_target_files.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_per_target_files.dot new file mode 100644 index 0000000..1bbf25a --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_per_target_files.dot @@ -0,0 +1,50 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "CompilerFlags", shape = pentagon ]; + "node1" [ label = "ConsoleApplication", shape = egg ]; + "node2" [ label = "CoreLibrary", shape = octagon ]; + "node2" -> "node0" // CoreLibrary -> CompilerFlags + "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary + "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary + "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ]; + "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary + "node5" [ label = "GraphicApplication", shape = egg ]; + "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary + "node6" [ label = "GraphicLibrary", shape = doubleoctagon ]; + "node7" [ label = "\"-lm\"", shape = septagon ]; + "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm" + "node6" -> "node0" // GraphicLibrary -> CompilerFlags + "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary + "node8" [ label = "GraphicLibraryObjects", shape = hexagon ]; + "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects + "node5" -> "node6" [ style = dotted ] // GraphicApplication -> GraphicLibrary + "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ]; + "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags + "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary + "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ]; + "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags + "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_shared_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_shared_libs.dot new file mode 100644 index 0000000..439d1f7 --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_shared_libs.dot @@ -0,0 +1,44 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "CompilerFlags", shape = pentagon ]; + "node1" [ label = "ConsoleApplication", shape = egg ]; + "node2" [ label = "CoreLibrary", shape = octagon ]; + "node2" -> "node0" // CoreLibrary -> CompilerFlags + "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary + "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary + "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ]; + "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary + "node5" [ label = "GraphicApplication", shape = egg ]; + "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary + "node6" [ label = "\"-lm\"", shape = septagon ]; + "node7" [ label = "GraphicLibraryObjects", shape = hexagon ]; + "node8" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ]; + "node8" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags + "node8" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary + "node9" [ label = "GraphicDriverVulkan", shape = tripleoctagon ]; + "node9" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags + "node9" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_static_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_static_libs.dot new file mode 100644 index 0000000..81199a2 --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_static_libs.dot @@ -0,0 +1,42 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "CompilerFlags", shape = pentagon ]; + "node1" [ label = "ConsoleApplication", shape = egg ]; + "node2" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "node3" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ]; + "node1" -> "node3" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary + "node4" [ label = "GraphicApplication", shape = egg ]; + "node5" [ label = "GraphicLibrary", shape = doubleoctagon ]; + "node6" [ label = "\"-lm\"", shape = septagon ]; + "node5" -> "node6" [ style = dotted ] // GraphicLibrary -> "-lm" + "node5" -> "node0" // GraphicLibrary -> CompilerFlags + "node7" [ label = "GraphicLibraryObjects", shape = hexagon ]; + "node5" -> "node7" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects + "node4" -> "node5" [ style = dotted ] // GraphicApplication -> GraphicLibrary + "node8" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ]; + "node8" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags + "node9" [ label = "GraphicDriverVulkan", shape = tripleoctagon ]; + "node9" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_unknown_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_unknown_libs.dot new file mode 100644 index 0000000..1be6550 --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_unknown_libs.dot @@ -0,0 +1,48 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "CompilerFlags", shape = pentagon ]; + "node1" [ label = "ConsoleApplication", shape = egg ]; + "node2" [ label = "CoreLibrary", shape = octagon ]; + "node2" -> "node0" // CoreLibrary -> CompilerFlags + "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary + "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary + "node4" [ label = "GraphicApplication", shape = egg ]; + "node4" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary + "node5" [ label = "GraphicLibrary", shape = doubleoctagon ]; + "node6" [ label = "\"-lm\"", shape = septagon ]; + "node5" -> "node6" [ style = dotted ] // GraphicLibrary -> "-lm" + "node5" -> "node0" // GraphicLibrary -> CompilerFlags + "node5" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary + "node7" [ label = "GraphicLibraryObjects", shape = hexagon ]; + "node5" -> "node7" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects + "node4" -> "node5" [ style = dotted ] // GraphicApplication -> GraphicLibrary + "node8" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ]; + "node8" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags + "node8" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary + "node9" [ label = "GraphicDriverVulkan", shape = tripleoctagon ]; + "node9" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags + "node9" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_header.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_header.dot new file mode 100644 index 0000000..1cfbe0f --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_header.dot @@ -0,0 +1,50 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "16" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "CompilerFlags", shape = pentagon ]; + "node1" [ label = "ConsoleApplication", shape = egg ]; + "node2" [ label = "CoreLibrary", shape = octagon ]; + "node2" -> "node0" // CoreLibrary -> CompilerFlags + "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary + "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary + "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ]; + "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary + "node5" [ label = "GraphicApplication", shape = egg ]; + "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary + "node6" [ label = "GraphicLibrary", shape = doubleoctagon ]; + "node7" [ label = "\"-lm\"", shape = septagon ]; + "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm" + "node6" -> "node0" // GraphicLibrary -> CompilerFlags + "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary + "node8" [ label = "GraphicLibraryObjects", shape = hexagon ]; + "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects + "node5" -> "node6" [ style = dotted ] // GraphicApplication -> GraphicLibrary + "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ]; + "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags + "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary + "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ]; + "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags + "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_name.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_name.dot new file mode 100644 index 0000000..9653c33 --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_name.dot @@ -0,0 +1,50 @@ +digraph "CMake Project Dependencies" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "node0" [ label = "CompilerFlags", shape = pentagon ]; + "node1" [ label = "ConsoleApplication", shape = egg ]; + "node2" [ label = "CoreLibrary", shape = octagon ]; + "node2" -> "node0" // CoreLibrary -> CompilerFlags + "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary + "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary + "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ]; + "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary + "node5" [ label = "GraphicApplication", shape = egg ]; + "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary + "node6" [ label = "GraphicLibrary", shape = doubleoctagon ]; + "node7" [ label = "\"-lm\"", shape = septagon ]; + "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm" + "node6" -> "node0" // GraphicLibrary -> CompilerFlags + "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary + "node8" [ label = "GraphicLibraryObjects", shape = hexagon ]; + "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects + "node5" -> "node6" [ style = dotted ] // GraphicApplication -> GraphicLibrary + "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ]; + "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags + "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary + "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ]; + "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags + "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary +} diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_node_prefix.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_node_prefix.dot new file mode 100644 index 0000000..82d96d0 --- /dev/null +++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_node_prefix.dot @@ -0,0 +1,50 @@ +digraph "GraphvizTestProject" { +node [ + fontsize = "12" +]; +subgraph clusterLegend { + label = "Legend"; + color = black; + edge [ style = invis ]; + legendNode0 [ label = "Executable", shape = egg ]; + legendNode1 [ label = "Static Library", shape = octagon ]; + legendNode2 [ label = "Shared Library", shape = doubleoctagon ]; + legendNode3 [ label = "Module Library", shape = tripleoctagon ]; + legendNode4 [ label = "Interface Library", shape = pentagon ]; + legendNode5 [ label = "Object Library", shape = hexagon ]; + legendNode6 [ label = "Unknown Library", shape = septagon ]; + legendNode7 [ label = "Custom Target", shape = box ]; + legendNode0 -> legendNode1 [ style = solid ]; + legendNode0 -> legendNode2 [ style = solid ]; + legendNode0 -> legendNode3; + legendNode1 -> legendNode4 [ label = "Interface", style = dashed ]; + legendNode2 -> legendNode5 [ label = "Private", style = dotted ]; + legendNode3 -> legendNode6 [ style = solid ]; + legendNode0 -> legendNode7; +} + "point0" [ label = "CompilerFlags", shape = pentagon ]; + "point1" [ label = "ConsoleApplication", shape = egg ]; + "point2" [ label = "CoreLibrary", shape = octagon ]; + "point2" -> "point0" // CoreLibrary -> CompilerFlags + "point3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ]; + "point2" -> "point3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary + "point1" -> "point2" [ style = dotted ] // ConsoleApplication -> CoreLibrary + "point4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ]; + "point1" -> "point4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary + "point5" [ label = "GraphicApplication", shape = egg ]; + "point5" -> "point2" [ style = dotted ] // GraphicApplication -> CoreLibrary + "point6" [ label = "GraphicLibrary", shape = doubleoctagon ]; + "point7" [ label = "\"-lm\"", shape = septagon ]; + "point6" -> "point7" [ style = dotted ] // GraphicLibrary -> "-lm" + "point6" -> "point0" // GraphicLibrary -> CompilerFlags + "point6" -> "point2" [ style = dotted ] // GraphicLibrary -> CoreLibrary + "point8" [ label = "GraphicLibraryObjects", shape = hexagon ]; + "point6" -> "point8" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects + "point5" -> "point6" [ style = dotted ] // GraphicApplication -> GraphicLibrary + "point9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ]; + "point9" -> "point0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags + "point9" -> "point2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary + "point10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ]; + "point10" -> "point0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags + "point10" -> "point2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary +} diff --git a/Tests/RunCMake/Graphviz/no_dependers_files-check.cmake b/Tests/RunCMake/Graphviz/no_dependers_files-check.cmake new file mode 100644 index 0000000..f4a43b6 --- /dev/null +++ b/Tests/RunCMake/Graphviz/no_dependers_files-check.cmake @@ -0,0 +1,4 @@ +file(GLOB dependers_files ${RunCMake_TEST_BINARY_DIR}/*.dependers) +if(${dependers_files}) + set(RunCMake_TEST_FAILED "Found *.dependers files despite GRAPHVIZ_GENERATE_DEPENDERS set to FALSE.") +endif() diff --git a/Tests/RunCMake/Graphviz/no_executables-check.cmake b/Tests/RunCMake/Graphviz/no_executables-check.cmake new file mode 100644 index 0000000..be29a4f --- /dev/null +++ b/Tests/RunCMake/Graphviz/no_executables-check.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +ensure_files_match( + ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_executables.dot + ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot) diff --git a/Tests/RunCMake/Graphviz/no_external_libs-check.cmake b/Tests/RunCMake/Graphviz/no_external_libs-check.cmake new file mode 100644 index 0000000..518ef7b --- /dev/null +++ b/Tests/RunCMake/Graphviz/no_external_libs-check.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +ensure_files_match( + ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_external_libs.dot + ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot) diff --git a/Tests/RunCMake/Graphviz/no_graphic_libs-check.cmake b/Tests/RunCMake/Graphviz/no_graphic_libs-check.cmake new file mode 100644 index 0000000..0f5aa47 --- /dev/null +++ b/Tests/RunCMake/Graphviz/no_graphic_libs-check.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +ensure_files_match( + ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_graphic_libs.dot + ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot) diff --git a/Tests/RunCMake/Graphviz/no_interface_libs-check.cmake b/Tests/RunCMake/Graphviz/no_interface_libs-check.cmake new file mode 100644 index 0000000..018fef0 --- /dev/null +++ b/Tests/RunCMake/Graphviz/no_interface_libs-check.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +ensure_files_match( + ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_interface_libs.dot + ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot) diff --git a/Tests/RunCMake/Graphviz/no_module_libs-check.cmake b/Tests/RunCMake/Graphviz/no_module_libs-check.cmake new file mode 100644 index 0000000..e185cb1 --- /dev/null +++ b/Tests/RunCMake/Graphviz/no_module_libs-check.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +ensure_files_match( + ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_module_libs.dot + ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot) diff --git a/Tests/RunCMake/Graphviz/no_object_libs-check.cmake b/Tests/RunCMake/Graphviz/no_object_libs-check.cmake new file mode 100644 index 0000000..90e7ecb --- /dev/null +++ b/Tests/RunCMake/Graphviz/no_object_libs-check.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +ensure_files_match( + ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_object_libs.dot + ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot) diff --git a/Tests/RunCMake/Graphviz/no_per_target_files-check.cmake b/Tests/RunCMake/Graphviz/no_per_target_files-check.cmake new file mode 100644 index 0000000..95d05a1 --- /dev/null +++ b/Tests/RunCMake/Graphviz/no_per_target_files-check.cmake @@ -0,0 +1,5 @@ +file(GLOB per_target_files ${RunCMake_TEST_BINARY_DIR}/*.dot.*) +list(FILTER per_target_files EXCLUDE REGEX ".*\\.dependers$") +if(per_target_files) + set(RunCMake_TEST_FAILED "Found per-target .dot files despite GRAPHVIZ_GENERATE_PER_TARGET set to FALSE.") +endif() diff --git a/Tests/RunCMake/Graphviz/no_shared_libs-check.cmake b/Tests/RunCMake/Graphviz/no_shared_libs-check.cmake new file mode 100644 index 0000000..b45da2e --- /dev/null +++ b/Tests/RunCMake/Graphviz/no_shared_libs-check.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +ensure_files_match( + ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_shared_libs.dot + ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot) diff --git a/Tests/RunCMake/Graphviz/no_static_libs-check.cmake b/Tests/RunCMake/Graphviz/no_static_libs-check.cmake new file mode 100644 index 0000000..befc11b --- /dev/null +++ b/Tests/RunCMake/Graphviz/no_static_libs-check.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +ensure_files_match( + ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_static_libs.dot + ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot) diff --git a/Tests/RunCMake/Graphviz/no_unknown_libs-check.cmake b/Tests/RunCMake/Graphviz/no_unknown_libs-check.cmake new file mode 100644 index 0000000..95286bc --- /dev/null +++ b/Tests/RunCMake/Graphviz/no_unknown_libs-check.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +ensure_files_match( + ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_unknown_libs.dot + ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot) diff --git a/Tests/RunCMake/Graphviz/set_graph_header-check.cmake b/Tests/RunCMake/Graphviz/set_graph_header-check.cmake new file mode 100644 index 0000000..1396484 --- /dev/null +++ b/Tests/RunCMake/Graphviz/set_graph_header-check.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +ensure_files_match( + ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_set_graph_header.dot + ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot) diff --git a/Tests/RunCMake/Graphviz/set_graph_name-check.cmake b/Tests/RunCMake/Graphviz/set_graph_name-check.cmake new file mode 100644 index 0000000..0c522e9 --- /dev/null +++ b/Tests/RunCMake/Graphviz/set_graph_name-check.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +ensure_files_match( + ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_set_graph_name.dot + ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot) diff --git a/Tests/RunCMake/Graphviz/set_node_prefix-check.cmake b/Tests/RunCMake/Graphviz/set_node_prefix-check.cmake new file mode 100644 index 0000000..61e9b24 --- /dev/null +++ b/Tests/RunCMake/Graphviz/set_node_prefix-check.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +ensure_files_match( + ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_set_node_prefix.dot + ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot) diff --git a/Tests/RunCMake/Graphviz/test_project/core_library.c b/Tests/RunCMake/Graphviz/test_project/core_library.c new file mode 100644 index 0000000..e8a8844 --- /dev/null +++ b/Tests/RunCMake/Graphviz/test_project/core_library.c @@ -0,0 +1,3 @@ +void log_something() +{ +} diff --git a/Tests/RunCMake/Graphviz/test_project/graphic_library.c b/Tests/RunCMake/Graphviz/test_project/graphic_library.c new file mode 100644 index 0000000..958c8ab --- /dev/null +++ b/Tests/RunCMake/Graphviz/test_project/graphic_library.c @@ -0,0 +1,3 @@ +void initialize_graphics() +{ +} diff --git a/Tests/RunCMake/Graphviz/test_project/main.c b/Tests/RunCMake/Graphviz/test_project/main.c new file mode 100644 index 0000000..d123e09 --- /dev/null +++ b/Tests/RunCMake/Graphviz/test_project/main.c @@ -0,0 +1,4 @@ +int main(int argc, char** argv) +{ + return 0; +} diff --git a/Tests/RunCMake/Graphviz/test_project/module.c b/Tests/RunCMake/Graphviz/test_project/module.c new file mode 100644 index 0000000..a508b09 --- /dev/null +++ b/Tests/RunCMake/Graphviz/test_project/module.c @@ -0,0 +1,3 @@ +static void some_function() +{ +} diff --git a/Tests/RunCMake/Graphviz/test_project/third_party_project/CMakeLists.txt b/Tests/RunCMake/Graphviz/test_project/third_party_project/CMakeLists.txt new file mode 100644 index 0000000..e381750 --- /dev/null +++ b/Tests/RunCMake/Graphviz/test_project/third_party_project/CMakeLists.txt @@ -0,0 +1,3 @@ +project(ThirdPartyProject) + +add_library(GoofyLoggingLibrary INTERFACE) diff --git a/Tests/RunCMake/PrecompileHeaders/PchMultilanguage-check.cmake b/Tests/RunCMake/PrecompileHeaders/PchMultilanguage-check.cmake index 44fe2da..e0b753a 100644 --- a/Tests/RunCMake/PrecompileHeaders/PchMultilanguage-check.cmake +++ b/Tests/RunCMake/PrecompileHeaders/PchMultilanguage-check.cmake @@ -15,3 +15,17 @@ if (NOT EXISTS ${foobar_pch_hxx_header}) set(RunCMake_TEST_FAILED "Generated foobar C++ pch header ${foobar_pch_hxx_header} does not exist") return() endif() + +file(STRINGS ${foobar_pch_h_header} foobar_pch_h_header_strings) + +if (NOT foobar_pch_h_header_strings MATCHES ";#include <stddef.h>(;|$)") + set(RunCMake_TEST_FAILED "Generated foo pch header\n ${foobar_pch_h_header}\nhas bad content:\n ${foobar_pch_h_header_strings}") + return() +endif() + +file(STRINGS ${foobar_pch_hxx_header} foobar_pch_hxx_header_strings) + +if (NOT foobar_pch_hxx_header_strings MATCHES ";#include <cstddef>(;|$)") + set(RunCMake_TEST_FAILED "Generated foo pch header\n ${foobar_pch_hxx_header}\nhas bad content:\n ${foobar_pch_hxx_header_strings}") + return() +endif() diff --git a/Tests/RunCMake/PrecompileHeaders/PchMultilanguage.cmake b/Tests/RunCMake/PrecompileHeaders/PchMultilanguage.cmake index 7a837da..cdc42b2 100644 --- a/Tests/RunCMake/PrecompileHeaders/PchMultilanguage.cmake +++ b/Tests/RunCMake/PrecompileHeaders/PchMultilanguage.cmake @@ -6,4 +6,7 @@ add_executable(foobar main.cpp ) target_include_directories(foobar PUBLIC include) -target_precompile_headers(foobar PRIVATE "<stddef.h>") +target_precompile_headers(foobar PRIVATE + "$<$<COMPILE_LANGUAGE:C>:<stddef.h$<ANGLE-R>>" + "$<$<COMPILE_LANGUAGE:CXX>:<cstddef$<ANGLE-R>>" + ) diff --git a/Tests/RunCMake/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake index da4d1e5..f24cfab 100644 --- a/Tests/RunCMake/RunCMake.cmake +++ b/Tests/RunCMake/RunCMake.cmake @@ -204,5 +204,28 @@ function(run_cmake_with_options test) run_cmake(${test}) endfunction() +function(ensure_files_match expected_file actual_file) + if(NOT EXISTS "${expected_file}") + message(FATAL_ERROR "Expected file does not exist:\n ${expected_file}") + endif() + if(NOT EXISTS "${actual_file}") + message(FATAL_ERROR "Actual file does not exist:\n ${actual_file}") + endif() + file(READ "${expected_file}" expected_file_content) + file(READ "${actual_file}" actual_file_content) + if(NOT "${expected_file_content}" STREQUAL "${actual_file_content}") + message(FATAL_ERROR "Actual file content does not match expected:\n + \n + expected file: ${expected_file}\n + expected content:\n + ${expected_file_content}\n + \n + actual file: ${actual_file}\n + actual content:\n + ${actual_file_content}\n + ") + endif() +endfunction() + # Protect RunCMake tests from calling environment. unset(ENV{MAKEFLAGS}) diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index 32b6829..1487161 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -15,6 +15,7 @@ run_cmake(VsDebuggerCommand) run_cmake(VsDebuggerCommandArguments) run_cmake(VsDebuggerEnvironment) run_cmake(VsCSharpCustomTags) +run_cmake(VsCSharpDocumentationFile) run_cmake(VsCSharpReferenceProps) run_cmake(VsCSharpWithoutSources) run_cmake(VsCSharpDeployFiles) diff --git a/Tests/RunCMake/VS10Project/VsCSharpDocumentationFile-check.cmake b/Tests/RunCMake/VS10Project/VsCSharpDocumentationFile-check.cmake new file mode 100644 index 0000000..0393362 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsCSharpDocumentationFile-check.cmake @@ -0,0 +1,26 @@ +# +# Check C# VS project for required elements +# +set(csProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.csproj") +if(NOT EXISTS "${csProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${csProjectFile} does not exist.") + return() +endif() + +file(STRINGS "${csProjectFile}" lines) + +set(HAVE_DocumentationFile 0) +foreach(line IN LISTS lines) + if(line MATCHES "^ *<DocumentationFile>([^<>]+)</DocumentationFile>") + if(HAVE_DocumentationFile) + set(RunCMake_TEST_FAILED "Documentation node has been generated more than once for\n ${csProjectFile}") + return() + endif() + set(HAVE_DocumentationFile 1) + endif() +endforeach() + +if(NOT HAVE_DocumentationFile) + set(RunCMake_TEST_FAILED "Documentation node has not been generated for\n ${csProjectFile}") + return() +endif() diff --git a/Tests/RunCMake/VS10Project/VsCSharpDocumentationFile.cmake b/Tests/RunCMake/VS10Project/VsCSharpDocumentationFile.cmake new file mode 100644 index 0000000..83b6b97 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsCSharpDocumentationFile.cmake @@ -0,0 +1,8 @@ +set(CMAKE_CONFIGURATION_TYPES Debug) +enable_language(CSharp) + +add_library(foo SHARED + foo.cs) + +set_target_properties(foo PROPERTIES + VS_DOTNET_DOCUMENTATION_FILE foo.xml) @@ -372,6 +372,7 @@ CMAKE_CXX_SOURCES="\ cmLDConfigTool \ cmLinkDirectoriesCommand \ cmLinkItem \ + cmLinkItemGraphVisitor \ cmLinkLineComputer \ cmLinkLineDeviceComputer \ cmListCommand \ |