diff options
384 files changed, 4767 insertions, 1662 deletions
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 381769d..fa2c23d 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -29,6 +29,8 @@ To contribute patches: #. Base all new work on the upstream ``master`` branch. Base work on the upstream ``release`` branch only if it fixes a regression or bug in a feature new to that release. + If in doubt, prefer ``master``. Reviewers may simply ask for + a rebase if deemed appropriate in particular cases. #. Create commits making incremental, distinct, logically complete changes with appropriate `commit messages`_. #. Push a topic branch to a personal repository fork on GitLab. diff --git a/CompileFlags.cmake b/CompileFlags.cmake index 32e7005..ec9b31b 100644 --- a/CompileFlags.cmake +++ b/CompileFlags.cmake @@ -82,3 +82,26 @@ endif () if (CMAKE_ANSI_CFLAGS) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ANSI_CFLAGS}") endif () + +# Allow per-translation-unit parallel builds when using MSVC +if(CMAKE_GENERATOR MATCHES "Visual Studio" AND + (CMAKE_C_COMPILER_ID MATCHES "MSVC|Intel" OR + CMAKE_CXX_COMPILER_ID MATCHES "MSVC|Intel")) + + set(CMake_MSVC_PARALLEL ON CACHE STRING "\ +Enables /MP flag for parallel builds using MSVC. Specify an \ +integer value to control the number of threads used (Only \ +works on some older versions of Visual Studio). Setting to \ +ON lets the toolchain decide how many threads to use. Set to \ +OFF to disable /MP completely." ) + + if(CMake_MSVC_PARALLEL) + if(CMake_MSVC_PARALLEL GREATER 0) + string(APPEND CMAKE_C_FLAGS " /MP${CMake_MSVC_PARALLEL}") + string(APPEND CMAKE_CXX_FLAGS " /MP${CMake_MSVC_PARALLEL}") + else() + string(APPEND CMAKE_C_FLAGS " /MP") + string(APPEND CMAKE_CXX_FLAGS " /MP") + endif() + endif() +endif() diff --git a/Help/command/COMPILE_OPTIONS_SHELL.txt b/Help/command/COMPILE_OPTIONS_SHELL.txt new file mode 100644 index 0000000..a1316c8 --- /dev/null +++ b/Help/command/COMPILE_OPTIONS_SHELL.txt @@ -0,0 +1,9 @@ +The final set of compile 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. +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 +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/FIND_XXX.txt b/Help/command/FIND_XXX.txt index 7db221c..13ea8ab 100644 --- a/Help/command/FIND_XXX.txt +++ b/Help/command/FIND_XXX.txt @@ -16,6 +16,7 @@ The general signature is: [PATH_SUFFIXES suffix1 [suffix2 ...]] [DOC "cache documentation string"] [NO_DEFAULT_PATH] + [NO_PACKAGE_ROOT_PATH] [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH] [NO_SYSTEM_ENVIRONMENT_PATH] @@ -60,6 +61,10 @@ If ``NO_DEFAULT_PATH`` is specified, then no additional paths are added to the search. If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows: +.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR| replace:: + |prefix_XXX_SUBDIR| for each ``<prefix>`` in ``PackageName_ROOT`` if called + from within a find module + .. |CMAKE_PREFIX_PATH_XXX_SUBDIR| replace:: |prefix_XXX_SUBDIR| for each ``<prefix>`` in :variable:`CMAKE_PREFIX_PATH` @@ -71,7 +76,19 @@ If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows: |prefix_XXX_SUBDIR| for each ``<prefix>`` in :variable:`CMAKE_SYSTEM_PREFIX_PATH` -1. Search paths specified in cmake-specific cache variables. +1. If called from within a find module, search prefix paths unique to the + current package being found. Specifically look in the ``PackageName_ROOT`` + CMake and environment variables. The package root variables are maintained + as a stack so if called from nested find modules, root paths from the + parent's find module will be searchd after paths from the current module, + i.e. ``CurrentPackage_ROOT``, ``ENV{CurrentPackage_ROOT}``, + ``ParentPackage_ROOT``, ``ENV{ParentPacakge_ROOT}``, etc. + This can be skipped if ``NO_PACKAGE_ROOT_PATH`` is passed. + See policy :policy:`CMP0074`. + + * |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX| + +2. Search paths specified in cmake-specific cache variables. These are intended to be used on the command line with a ``-DVAR=value``. The values are interpreted as :ref:`;-lists <CMake Language Lists>`. This can be skipped if ``NO_CMAKE_PATH`` is passed. @@ -80,7 +97,7 @@ If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows: * |CMAKE_XXX_PATH| * |CMAKE_XXX_MAC_PATH| -2. Search paths specified in cmake-specific environment variables. +3. Search paths specified in cmake-specific environment variables. These are intended to be set in the user's shell configuration, and therefore use the host's native path separator (``;`` on Windows and ``:`` on UNIX). @@ -90,17 +107,17 @@ If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows: * |CMAKE_XXX_PATH| * |CMAKE_XXX_MAC_PATH| -3. Search the paths specified by the ``HINTS`` option. +4. Search the paths specified by the ``HINTS`` option. These should be paths computed by system introspection, such as a hint provided by the location of another item already found. Hard-coded guesses should be specified with the ``PATHS`` option. -4. Search the standard system environment variables. +5. Search the standard system environment variables. This can be skipped if ``NO_SYSTEM_ENVIRONMENT_PATH`` is an argument. * |SYSTEM_ENVIRONMENT_PATH_XXX| -5. Search cmake variables defined in the Platform files +6. Search cmake variables defined in the Platform files for the current system. This can be skipped if ``NO_CMAKE_SYSTEM_PATH`` is passed. @@ -108,7 +125,7 @@ If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows: * |CMAKE_SYSTEM_XXX_PATH| * |CMAKE_SYSTEM_XXX_MAC_PATH| -6. Search the paths specified by the PATHS option +7. Search the paths specified by the PATHS option or in the short-hand version of the command. These are typically hard-coded guesses. diff --git a/Help/command/add_compile_options.rst b/Help/command/add_compile_options.rst index 3fe2a33..44924e6 100644 --- a/Help/command/add_compile_options.rst +++ b/Help/command/add_compile_options.rst @@ -21,3 +21,5 @@ Arguments to ``add_compile_options`` may use "generator expressions" with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual for available expressions. See the :manual:`cmake-buildsystem(7)` manual for more on defining buildsystem properties. + +.. include:: COMPILE_OPTIONS_SHELL.txt diff --git a/Help/command/add_library.rst b/Help/command/add_library.rst index 3706153..8fa0df7 100644 --- a/Help/command/add_library.rst +++ b/Help/command/add_library.rst @@ -110,10 +110,10 @@ along with those compiled from their own sources. Object libraries may contain only sources that compile, header files, and other files that would not affect linking of a normal library (e.g. ``.txt``). They may contain custom commands generating such sources, but not -``PRE_BUILD``, ``PRE_LINK``, or ``POST_BUILD`` commands. Object libraries -cannot be linked. Some native build systems (such as Xcode) may not like -targets that have only object files, so consider adding at least one real -source file to any target that references ``$<TARGET_OBJECTS:objlib>``. +``PRE_BUILD``, ``PRE_LINK``, or ``POST_BUILD`` commands. Some native build +systems (such as Xcode) may not like targets that have only object files, so +consider adding at least one real source file to any target that references +``$<TARGET_OBJECTS:objlib>``. Alias Libraries ^^^^^^^^^^^^^^^ diff --git a/Help/command/export.rst b/Help/command/export.rst index 53675a7..0c676c6 100644 --- a/Help/command/export.rst +++ b/Help/command/export.rst @@ -40,6 +40,15 @@ policy CMP0022 is NEW. If a library target is included in the export but a target to which it links is not included the behavior is unspecified. +.. note:: + + :ref:`Object Libraries` under :generator:`Xcode` have special handling if + multiple architectures are listed in :variable:`CMAKE_OSX_ARCHITECTURES`. + In this case they will be exported as :ref:`Interface Libraries` with + no object files available to clients. This is sufficient to satisfy + transitive usage requirements of other targets that link to the + object libraries in their implementation. + :: export(PACKAGE <name>) diff --git a/Help/command/file.rst b/Help/command/file.rst index 5ce86e5..5e18077 100644 --- a/Help/command/file.rst +++ b/Help/command/file.rst @@ -285,6 +285,23 @@ If neither ``TLS`` option is given CMake will check variables :: + file(TOUCH [<files>...]) + file(TOUCH_NOCREATE [<files>...]) + +Create a file with no content if it does not yet exist. If the file already +exists, its access and/or modification will be updated to the time when the +function call is executed. + +Use TOUCH_NOCREATE to touch a file if it exists but not create it. If a file +does not exist it will be silently ignored. + +With TOUCH and TOUCH_NOCREATE the contents of an existing file will not be +modified. + +------------------------------------------------------------------------------ + +:: + file(TIMESTAMP <filename> <variable> [<format>] [UTC]) Compute a string representation of the modification time of ``<filename>`` diff --git a/Help/command/find_file.rst b/Help/command/find_file.rst index e56097b..2a14ad7 100644 --- a/Help/command/find_file.rst +++ b/Help/command/find_file.rst @@ -8,6 +8,9 @@ find_file .. |prefix_XXX_SUBDIR| replace:: ``<prefix>/include`` .. |entry_XXX_SUBDIR| replace:: ``<entry>/include`` +.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX| replace:: + ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE` + is set, and |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR| .. |CMAKE_PREFIX_PATH_XXX| replace:: ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE` is set, and |CMAKE_PREFIX_PATH_XXX_SUBDIR| diff --git a/Help/command/find_library.rst b/Help/command/find_library.rst index f774f17..0861d67 100644 --- a/Help/command/find_library.rst +++ b/Help/command/find_library.rst @@ -8,6 +8,9 @@ find_library .. |prefix_XXX_SUBDIR| replace:: ``<prefix>/lib`` .. |entry_XXX_SUBDIR| replace:: ``<entry>/lib`` +.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX| replace:: + ``<prefix>/lib/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE` is set, + and |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR| .. |CMAKE_PREFIX_PATH_XXX| replace:: ``<prefix>/lib/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE` is set, and |CMAKE_PREFIX_PATH_XXX_SUBDIR| diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst index b2e70f2..89c5a7a 100644 --- a/Help/command/find_package.rst +++ b/Help/command/find_package.rst @@ -64,6 +64,7 @@ The complete Config mode command signature is:: [PATHS path1 [path2 ... ]] [PATH_SUFFIXES suffix1 [suffix2 ...]] [NO_DEFAULT_PATH] + [NO_PACKAGE_ROOT_PATH] [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH] [NO_SYSTEM_ENVIRONMENT_PATH] @@ -249,7 +250,14 @@ The set of installation prefixes is constructed using the following steps. If ``NO_DEFAULT_PATH`` is specified all ``NO_*`` options are enabled. -1. Search paths specified in cmake-specific cache variables. These +1. Search paths specified in the ``PackageName_ROOT`` CMake and environment + variables. The package root variables are maintained as a stack so if + called from within a find module, root paths from the parent's find + module will also be searched after paths for the current package. + This can be skipped if ``NO_PACKAGE_ROOT_PATH`` is passed. + See policy :policy:`CMP0074`. + +2. Search paths specified in cmake-specific cache variables. These are intended to be used on the command line with a ``-DVAR=value``. The values are interpreted as :ref:`;-lists <CMake Language Lists>`. This can be skipped if ``NO_CMAKE_PATH`` is passed:: @@ -258,7 +266,7 @@ enabled. CMAKE_FRAMEWORK_PATH CMAKE_APPBUNDLE_PATH -2. Search paths specified in cmake-specific environment variables. +3. Search paths specified in cmake-specific environment variables. These are intended to be set in the user's shell configuration, and therefore use the host's native path separator (``;`` on Windows and ``:`` on UNIX). @@ -269,26 +277,26 @@ enabled. CMAKE_FRAMEWORK_PATH CMAKE_APPBUNDLE_PATH -3. Search paths specified by the ``HINTS`` option. These should be paths +4. Search paths specified by the ``HINTS`` option. These should be paths computed by system introspection, such as a hint provided by the location of another item already found. Hard-coded guesses should be specified with the ``PATHS`` option. -4. Search the standard system environment variables. This can be +5. Search the standard system environment variables. This can be skipped if ``NO_SYSTEM_ENVIRONMENT_PATH`` is passed. Path entries ending in ``/bin`` or ``/sbin`` are automatically converted to their parent directories:: PATH -5. Search paths stored in the CMake :ref:`User Package Registry`. +6. Search paths stored in the CMake :ref:`User Package Registry`. This can be skipped if ``NO_CMAKE_PACKAGE_REGISTRY`` is passed or by setting the :variable:`CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY` to ``TRUE``. See the :manual:`cmake-packages(7)` manual for details on the user package registry. -6. Search cmake variables defined in the Platform files for the +7. Search cmake variables defined in the Platform files for the current system. This can be skipped if ``NO_CMAKE_SYSTEM_PATH`` is passed:: @@ -296,14 +304,14 @@ enabled. CMAKE_SYSTEM_FRAMEWORK_PATH CMAKE_SYSTEM_APPBUNDLE_PATH -7. Search paths stored in the CMake :ref:`System Package Registry`. +8. Search paths stored in the CMake :ref:`System Package Registry`. This can be skipped if ``NO_CMAKE_SYSTEM_PACKAGE_REGISTRY`` is passed or by setting the :variable:`CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY` to ``TRUE``. See the :manual:`cmake-packages(7)` manual for details on the system package registry. -8. Search paths specified by the ``PATHS`` option. These are typically +9. Search paths specified by the ``PATHS`` option. These are typically hard-coded guesses. .. |FIND_XXX| replace:: find_package diff --git a/Help/command/find_path.rst b/Help/command/find_path.rst index 76342d0..988a3fa 100644 --- a/Help/command/find_path.rst +++ b/Help/command/find_path.rst @@ -8,6 +8,9 @@ find_path .. |prefix_XXX_SUBDIR| replace:: ``<prefix>/include`` .. |entry_XXX_SUBDIR| replace:: ``<entry>/include`` +.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX| replace:: + ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE` + is set, and |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR| .. |CMAKE_PREFIX_PATH_XXX| replace:: ``<prefix>/include/<arch>`` if :variable:`CMAKE_LIBRARY_ARCHITECTURE` is set, and |CMAKE_PREFIX_PATH_XXX_SUBDIR| diff --git a/Help/command/find_program.rst b/Help/command/find_program.rst index d3430c0..4f00773 100644 --- a/Help/command/find_program.rst +++ b/Help/command/find_program.rst @@ -8,6 +8,8 @@ find_program .. |prefix_XXX_SUBDIR| replace:: ``<prefix>/[s]bin`` .. |entry_XXX_SUBDIR| replace:: ``<entry>/[s]bin`` +.. |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX| replace:: + |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX_SUBDIR| .. |CMAKE_PREFIX_PATH_XXX| replace:: |CMAKE_PREFIX_PATH_XXX_SUBDIR| .. |CMAKE_XXX_PATH| replace:: :variable:`CMAKE_PROGRAM_PATH` diff --git a/Help/command/install.rst b/Help/command/install.rst index 2506f98..eb7b07c 100644 --- a/Help/command/install.rst +++ b/Help/command/install.rst @@ -183,6 +183,13 @@ export called ``<export-name>``. It must appear before any ``RUNTIME``, ``LIBRARY``, ``ARCHIVE``, or ``OBJECTS`` options. To actually install the export file itself, call ``install(EXPORT)``, documented below. +:ref:`Interface Libraries` may be listed among the targets to install. +They install no artifacts but will be included in an associated ``EXPORT``. +If :ref:`Object Libraries` are listed but given no destination for their +object files, they will be exported as :ref:`Interface Libraries`. +This is sufficient to satisfy transitive usage requirements of other +targets that link to the object libraries in their implementation. + Installing a target with the :prop_tgt:`EXCLUDE_FROM_ALL` target property set to ``TRUE`` has undefined behavior. diff --git a/Help/command/list.rst b/Help/command/list.rst index f6b75bc..e6a7069 100644 --- a/Help/command/list.rst +++ b/Help/command/list.rst @@ -1,68 +1,151 @@ list ---- +.. only:: html + + .. contents:: + List operations. +The list subcommands ``APPEND``, ``INSERT``, ``FILTER``, ``REMOVE_AT``, +``REMOVE_ITEM``, ``REMOVE_DUPLICATES``, ``REVERSE`` and ``SORT`` may create +new values for the list within the current CMake variable scope. Similar to +the :command:`set` command, the LIST command creates new variable values in +the current scope, even if the list itself is actually defined in a parent +scope. To propagate the results of these operations upwards, use +:command:`set` with ``PARENT_SCOPE``, :command:`set` with +``CACHE INTERNAL``, or some other means of value propagation. + +.. note:: + + A list in cmake is a ``;`` separated group of strings. To create a + list the set command can be used. For example, ``set(var a b c d e)`` + creates a list with ``a;b;c;d;e``, and ``set(var "a b c d e")`` creates a + string or a list with one item in it. (Note macro arguments are not + variables, and therefore cannot be used in LIST commands.) + +.. note:: + + When specifying index values, if ``<element index>`` is 0 or greater, it + is indexed from the beginning of the list, with 0 representing the + first list element. If ``<element index>`` is -1 or lesser, it is indexed + from the end of the list, with -1 representing the last list element. + Be careful when counting with negative indices: they do not start from + 0. -0 is equivalent to 0, the first list element. + +Capacity and Element access +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +LENGTH +"""""" + :: list(LENGTH <list> <output variable>) - list(GET <list> <element index> [<element index> ...] - <output variable>) + +Returns the list's length. + +GET +""" + +:: + + list(GET <list> <element index> [<element index> ...] <output variable>) + +Returns the list of elements specified by indices from the list. + +Search +^^^^^^ + +FIND +"""" + +:: + + list(FIND <list> <value> <output variable>) + +Returns the index of the element specified in the list or -1 +if it wasn't found. + +Modification +^^^^^^^^^^^^ + +APPEND +"""""" + +:: + list(APPEND <list> [<element> ...]) + +Appends elements to the list. + +FILTER +"""""" + +:: + list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regular_expression>) - list(FIND <list> <value> <output variable>) + +Includes or removes items from the list that match the mode's pattern. +In ``REGEX`` mode, items will be matched against the given regular expression. + +For more information on regular expressions see also the +:command:`string` command. + +INSERT +"""""" + +:: + list(INSERT <list> <element_index> <element> [<element> ...]) + +Inserts elements to the list to the specified location. + +REMOVE_ITEM +""""""""""" + +:: + list(REMOVE_ITEM <list> <value> [<value> ...]) + +Removes the given items from the list. + +REMOVE_AT +""""""""" + +:: + list(REMOVE_AT <list> <index> [<index> ...]) - list(REMOVE_DUPLICATES <list>) - list(REVERSE <list>) - list(SORT <list>) -``LENGTH`` will return a given list's length. +Removes items at given indices from the list. -``GET`` will return list of elements specified by indices from the list. +REMOVE_DUPLICATES +""""""""""""""""" -``APPEND`` will append elements to the list. +:: -``FILTER`` will include or remove items from the list that match the -mode's pattern. -In ``REGEX`` mode, items will be matched against the given regular expression. -For more information on regular expressions see also the :command:`string` -command. + list(REMOVE_DUPLICATES <list>) -``FIND`` will return the index of the element specified in the list or -1 -if it wasn't found. +Removes duplicated items in the list. + +Sorting +^^^^^^^ + +REVERSE +""""""" -``INSERT`` will insert elements to the list to the specified location. +:: -``REMOVE_AT`` and ``REMOVE_ITEM`` will remove items from the list. The -difference is that ``REMOVE_ITEM`` will remove the given items, while -``REMOVE_AT`` will remove the items at the given indices. + list(REVERSE <list>) -``REMOVE_DUPLICATES`` will remove duplicated items in the list. +Reverses the contents of the list in-place. -``REVERSE`` reverses the contents of the list in-place. +SORT +"""" -``SORT`` sorts the list in-place alphabetically. +:: + + list(SORT <list>) -The list subcommands ``APPEND``, ``INSERT``, ``FILTER``, ``REMOVE_AT``, -``REMOVE_ITEM``, ``REMOVE_DUPLICATES``, ``REVERSE`` and ``SORT`` may create new -values for the list within the current CMake variable scope. Similar to the -:command:`set` command, the LIST command creates new variable values in the -current scope, even if the list itself is actually defined in a parent -scope. To propagate the results of these operations upwards, use -:command:`set` with ``PARENT_SCOPE``, :command:`set` with -``CACHE INTERNAL``, or some other means of value propagation. -NOTES: A list in cmake is a ``;`` separated group of strings. To create a -list the set command can be used. For example, ``set(var a b c d e)`` -creates a list with ``a;b;c;d;e``, and ``set(var "a b c d e")`` creates a -string or a list with one item in it. (Note macro arguments are not -variables, and therefore cannot be used in LIST commands.) - -When specifying index values, if ``<element index>`` is 0 or greater, it -is indexed from the beginning of the list, with 0 representing the -first list element. If ``<element index>`` is -1 or lesser, it is indexed -from the end of the list, with -1 representing the last list element. -Be careful when counting with negative indices: they do not start from -0. -0 is equivalent to 0, the first list element. +Sorts the list in-place alphabetically. diff --git a/Help/command/project.rst b/Help/command/project.rst index eb185e4..e46dd69 100644 --- a/Help/command/project.rst +++ b/Help/command/project.rst @@ -1,7 +1,7 @@ project ------- -Set a name, version, and enable languages for the entire project. +Sets project details such as name, version, etc. and enables languages. .. code-block:: cmake @@ -9,6 +9,7 @@ Set a name, version, and enable languages for the entire project. project(<PROJECT-NAME> [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]] [DESCRIPTION <project-description-string>] + [HOMEPAGE_URL <url-string>] [LANGUAGES <language-name>...]) Sets the name of the project and stores the name in the @@ -41,9 +42,18 @@ in variables Variables corresponding to unspecified versions are set to the empty string (if policy :policy:`CMP0048` is set to ``NEW``). -If optional ``DESCRIPTION`` is given, then additional :variable:`PROJECT_DESCRIPTION` -variable will be set to its argument. The argument must be a string with short -description of the project (only a few words). +If the optional ``DESCRIPTION`` is given, then :variable:`PROJECT_DESCRIPTION` +and :variable:`<PROJECT-NAME>_DESCRIPTION` will be set to its argument. +The description is expected to be a relatively short string, usually no more +than a few words. + +The optional ``HOMEPAGE_URL`` sets the analogous variables +:variable:`PROJECT_HOMEPAGE_URL` and :variable:`<PROJECT-NAME>_HOMEPAGE_URL`. +When this option is given, the URL provided should be the canonical home for +the project. + +Note that the description and homepage URL may be used as defaults for +things like packaging meta-data, documentation, etc. Optionally you can specify which languages your project supports. Example languages include ``C``, ``CXX`` (i.e. C++), ``CUDA``, @@ -63,7 +73,11 @@ The top-level ``CMakeLists.txt`` file for a project must contain a literal, direct call to the :command:`project` command; loading one through the :command:`include` command is not sufficient. If no such call exists CMake will implicitly add one to the top that enables the -default languages (``C`` and ``CXX``). +default languages (``C`` and ``CXX``). The name of the project set in +the top level ``CMakeLists.txt`` file is available from the +:variable:`CMAKE_PROJECT_NAME` variable, its description from +:variable:`CMAKE_PROJECT_DESCRIPTION` and its homepage URL from +:variable:`CMAKE_PROJECT_HOMEPAGE_URL`. .. note:: Call the :command:`cmake_minimum_required` command at the beginning diff --git a/Help/command/string.rst b/Help/command/string.rst index fb3893f..cd94bb4 100644 --- a/Help/command/string.rst +++ b/Help/command/string.rst @@ -151,6 +151,16 @@ CONCAT Concatenate all the input arguments together and store the result in the named output variable. +JOIN +"""" + +:: + + string(JOIN <glue> <output variable> [<input>...]) + +Join all the input arguments together using the glue +string and store the result in the named output variable. + TOLOWER """"""" @@ -282,6 +292,18 @@ CONFIGURE Transform a string like :command:`configure_file` transforms a file. +MAKE_C_IDENTIFIER +""""""""""""""""" + +:: + + string(MAKE_C_IDENTIFIER <input string> <output variable>) + +Convert each non-alphanumeric character in the ``<input string>`` to an +underscore and store the result in the ``<output variable>``. If the first +character of the string is a digit, an underscore will also be prepended to +the result. + RANDOM """""" @@ -346,13 +368,6 @@ If no explicit ``<format string>`` is given it will default to: %Y-%m-%dT%H:%M:%S for local time. %Y-%m-%dT%H:%M:%SZ for UTC. - -:: - - string(MAKE_C_IDENTIFIER <input string> <output variable>) - -Write a string which can be used as an identifier in C. - .. note:: If the ``SOURCE_DATE_EPOCH`` environment variable is set, diff --git a/Help/command/target_compile_options.rst b/Help/command/target_compile_options.rst index 3e7dc47..b7b4dc1 100644 --- a/Help/command/target_compile_options.rst +++ b/Help/command/target_compile_options.rst @@ -38,3 +38,5 @@ Arguments to ``target_compile_options`` may use "generator expressions" with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual for available expressions. See the :manual:`cmake-buildsystem(7)` manual for more on defining buildsystem properties. + +.. include:: COMPILE_OPTIONS_SHELL.txt diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst index 2ec8744..fcc2c07 100644 --- a/Help/command/target_link_libraries.rst +++ b/Help/command/target_link_libraries.rst @@ -183,6 +183,70 @@ is not ``NEW``, they are also appended to the ``general`` (or without any keyword) are treated as if specified for both ``debug`` and ``optimized``. +Linking Object Libraries +^^^^^^^^^^^^^^^^^^^^^^^^ + +:ref:`Object Libraries` may be used as the ``<target>`` (first) argument +of ``target_link_libraries`` to specify dependencies of their sources +on other libraries. For example, the code + +.. code-block:: cmake + + add_library(A SHARED a.c) + target_compile_definitions(A PUBLIC A) + + add_library(obj OBJECT obj.c) + target_compile_definitions(obj PUBLIC OBJ) + target_link_libraries(obj PUBLIC A) + +compiles ``obj.c`` with ``-DA -DOBJ`` and establishes usage requirements +for ``obj`` that propagate to its dependents. + +Normal libraries and executables may link to :ref:`Object Libraries` +to get their objects and usage requirements. Continuing the above +example, the code + +.. code-block:: cmake + + add_library(B SHARED b.c) + target_link_libraries(B PUBLIC obj) + +compiles ``b.c`` with ``-DA -DOBJ``, creates shared library ``B`` +with object files from ``b.c`` and ``obj.c``, and links ``B`` to ``A``. +Furthermore, the code + +.. code-block:: cmake + + add_executable(main main.c) + target_link_libraries(main B) + +compiles ``main.c`` with ``-DA -DOBJ`` and links executable ``main`` +to ``B`` and ``A``. The object library's usage requirements are +propagated transitively through ``B``, but its object files are not. + +:ref:`Object Libraries` may "link" to other object libraries to get +usage requirements, but since they do not have a link step nothing +is done with their object files. Continuing from the above example, +the code: + +.. code-block:: cmake + + add_library(obj2 OBJECT obj2.c) + target_link_libraries(obj2 PUBLIC obj) + + add_executable(main2 main2.c) + target_link_libraries(main2 obj2) + +compiles ``obj2.c`` with ``-DA -DOBJ``, creates executable ``main2`` +with object files from ``main2.c`` and ``obj2.c``, and links ``main2`` +to ``A``. + +In other words, when :ref:`Object Libraries` appear in a target's +:prop_tgt:`INTERFACE_LINK_LIBRARIES` property they will be +treated as :ref:`Interface Libraries`, but when they appear in +a target's :prop_tgt:`LINK_LIBRARIES` property their object files +will be included in the link too. + Cyclic Dependencies of Static Libraries ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Help/manual/cmake-buildsystem.7.rst b/Help/manual/cmake-buildsystem.7.rst index b672ea6..50c4087 100644 --- a/Help/manual/cmake-buildsystem.7.rst +++ b/Help/manual/cmake-buildsystem.7.rst @@ -113,9 +113,9 @@ and it uniquely identifies the bundle. Object Libraries ^^^^^^^^^^^^^^^^ -The ``OBJECT`` library type is also not linked to. It defines a non-archival -collection of object files resulting from compiling the given source files. -The object files collection can be used as source inputs to other targets: +The ``OBJECT`` library type defines a non-archival collection of object files +resulting from compiling the given source files. The object files collection +may be used as source inputs to other targets: .. code-block:: cmake @@ -125,22 +125,31 @@ The object files collection can be used as source inputs to other targets: add_executable(test_exe $<TARGET_OBJECTS:archive> test.cpp) -``OBJECT`` libraries may not be used in the right hand side of -:command:`target_link_libraries`. They also may not be used as the ``TARGET`` -in a use of the :command:`add_custom_command(TARGET)` command signature. They -may be installed, and will be exported as an INTERFACE library. +The link (or archiving) step of those other targets will use the object +files collection in addition to those from their own sources. -Although object libraries may not be named directly in calls to -the :command:`target_link_libraries` command, they can be "linked" -indirectly by using an :ref:`Interface Library <Interface Libraries>` -whose :prop_tgt:`INTERFACE_SOURCES` target property is set to name -``$<TARGET_OBJECTS:objlib>``. +Alternatively, object libraries may be linked into other targets: -Although object libraries may not be used as the ``TARGET`` -in a use of the :command:`add_custom_command(TARGET)` command signature, -the list of objects can be used by :command:`add_custom_command(OUTPUT)` or -:command:`file(GENERATE)` by using ``$<TARGET_OBJECTS:objlib>``. +.. code-block:: cmake + + add_library(archive OBJECT archive.cpp zip.cpp lzma.cpp) + + add_library(archiveExtras STATIC extras.cpp) + target_link_libraries(archiveExtras PUBLIC archive) + + add_executable(test_exe test.cpp) + target_link_libraries(test_exe archive) + +The link (or archiving) step of those other targets will use the object +files from object libraries that are *directly* linked. Additionally, +usage requirements of the object libraries will be honored when compiling +sources in those other targets. Furthermore, those usage requirements +will propagate transitively to dependents of those other targets. +Object libraries may not be used as the ``TARGET`` in a use of the +:command:`add_custom_command(TARGET)` command signature. However, +the list of objects can be used by :command:`add_custom_command(OUTPUT)` +or :command:`file(GENERATE)` by using ``$<TARGET_OBJECTS:objlib>``. Build Specification and Usage Requirements ========================================== diff --git a/Help/manual/cmake-developer.7.rst b/Help/manual/cmake-developer.7.rst index cd509ac..41fe90c 100644 --- a/Help/manual/cmake-developer.7.rst +++ b/Help/manual/cmake-developer.7.rst @@ -943,7 +943,7 @@ populated: endif() The ``RELEASE`` variant should be listed first in the property -so that that variant is chosen if the user uses a configuration which is +so that the variant is chosen if the user uses a configuration which is not an exact match for any listed ``IMPORTED_CONFIGURATIONS``. Most of the cache variables should be hidden in the ``ccmake`` interface unless diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index 0f6d4cf..d3514ab 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -57,6 +57,10 @@ Available logical expressions are: ``1`` if ``a`` is STREQUAL ``b``, else ``0`` ``$<EQUAL:a,b>`` ``1`` if ``a`` is EQUAL ``b`` in a numeric comparison, else ``0`` +``$<IN_LIST:a,b>`` + ``1`` if ``a`` is IN_LIST ``b``, else ``0`` +``$<TARGET_EXISTS:tgt>`` + ``1`` if ``tgt`` is an existed target name, else ``0``. ``$<CONFIG:cfg>`` ``1`` if config is ``cfg``, else ``0``. This is a case-insensitive comparison. The mapping in :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` is also considered by @@ -289,7 +293,8 @@ Available output expressions are: ``$<UPPER_CASE:...>`` Content of ``...`` converted to upper case. ``$<MAKE_C_IDENTIFIER:...>`` - Content of ``...`` converted to a C identifier. + Content of ``...`` converted to a C identifier. The conversion follows the + same behavior as :command:`string(MAKE_C_IDENTIFIER)`. ``$<TARGET_OBJECTS:objLib>`` List of objects resulting from build of ``objLib``. ``objLib`` must be an object of type ``OBJECT_LIBRARY``. diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index 96d5c7d..7e2255d 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -51,6 +51,15 @@ The :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` variable may also be used to determine whether to report an error on use of deprecated macros or functions. +Policies Introduced by CMake 3.12 +================================= + +.. toctree:: + :maxdepth: 1 + + CMP0074: find_package uses PackageName_ROOT variables. </policy/CMP0074> + CMP0073: Do not produce legacy _LIB_DEPENDS cache entries. </policy/CMP0073> + Policies Introduced by CMake 3.11 ================================= diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 00a932f..7ace270 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -84,6 +84,7 @@ Properties on Directories /prop_dir/RULE_LAUNCH_LINK /prop_dir/SOURCE_DIR /prop_dir/SUBDIRECTORIES + /prop_dir/TESTS /prop_dir/TEST_INCLUDE_FILES /prop_dir/VARIABLES /prop_dir/VS_GLOBAL_SECTION_POST_section @@ -175,6 +176,7 @@ Properties on Targets /prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG /prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD /prop_tgt/EXPORT_NAME + /prop_tgt/EXPORT_PROPERTIES /prop_tgt/FOLDER /prop_tgt/Fortran_FORMAT /prop_tgt/Fortran_MODULE_DIRECTORY @@ -295,6 +297,7 @@ Properties on Targets /prop_tgt/VISIBILITY_INLINES_HIDDEN /prop_tgt/VS_CONFIGURATION_TYPE /prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY + /prop_tgt/VS_DEBUGGER_COMMAND /prop_tgt/VS_DESKTOP_EXTENSIONS_VERSION /prop_tgt/VS_DOTNET_REFERENCE_refname /prop_tgt/VS_DOTNET_REFERENCEPROP_refname_TAG_tagname @@ -347,6 +350,7 @@ Properties on Tests /prop_test/LABELS /prop_test/MEASUREMENT /prop_test/PASS_REGULAR_EXPRESSION + /prop_test/PROCESSOR_AFFINITY /prop_test/PROCESSORS /prop_test/REQUIRED_FILES /prop_test/RESOURCE_LOCK diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 3ac5123..0cb90d4 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -67,6 +67,7 @@ Variables that Provide Information /variable/CMAKE_PARENT_LIST_FILE /variable/CMAKE_PATCH_VERSION /variable/CMAKE_PROJECT_DESCRIPTION + /variable/CMAKE_PROJECT_HOMEPAGE_URL /variable/CMAKE_PROJECT_NAME /variable/CMAKE_RANLIB /variable/CMAKE_ROOT @@ -97,6 +98,8 @@ Variables that Provide Information /variable/CMAKE_XCODE_GENERATE_SCHEME /variable/CMAKE_XCODE_PLATFORM_TOOLSET /variable/PROJECT-NAME_BINARY_DIR + /variable/PROJECT-NAME_DESCRIPTION + /variable/PROJECT-NAME_HOMEPAGE_URL /variable/PROJECT-NAME_SOURCE_DIR /variable/PROJECT-NAME_VERSION /variable/PROJECT-NAME_VERSION_MAJOR @@ -105,6 +108,7 @@ Variables that Provide Information /variable/PROJECT-NAME_VERSION_TWEAK /variable/PROJECT_BINARY_DIR /variable/PROJECT_DESCRIPTION + /variable/PROJECT_HOMEPAGE_URL /variable/PROJECT_NAME /variable/PROJECT_SOURCE_DIR /variable/PROJECT_VERSION @@ -178,6 +182,7 @@ Variables that Change Behavior /variable/CMAKE_STAGING_PREFIX /variable/CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS /variable/CMAKE_SUBLIME_TEXT_2_EXCLUDE_BUILD_TREE + /variable/CMAKE_SUPPRESS_REGENERATION /variable/CMAKE_SYSROOT /variable/CMAKE_SYSROOT_COMPILE /variable/CMAKE_SYSROOT_LINK diff --git a/Help/manual/ctest.1.rst b/Help/manual/ctest.1.rst index a04c403..75af22e 100644 --- a/Help/manual/ctest.1.rst +++ b/Help/manual/ctest.1.rst @@ -368,15 +368,17 @@ for "SubprojectB"). Build and Test Mode =================== -CTest provides a command-line signature to to configure (i.e. run cmake on), -build, and or execute a test:: +CTest provides a command-line signature to configure (i.e. run cmake on), +build, and/or execute a test:: ctest --build-and-test <path-to-source> <path-to-build> - --build-generator <generator> [<options>...] [-- <build-options>...] - [--test-command <test>] + --build-generator <generator> + [<options>...] + [--build-options <opts>...] + [--test-command <command> [<args>...]] The configure and test steps are optional. The arguments to this command line -are the source and binary directories. The ``--build-generator`` option *must* +are the source and binary directories. The ``--build-generator`` option *must* be provided to use ``--build-and-test``. If ``--test-command`` is specified then that will be run after the build is complete. Other options that affect this mode include: @@ -425,13 +427,15 @@ this mode include: should be used. e.g. Debug/Release/etc. ``--build-options`` - Add extra options to the build step. - - This option must be the last option with the exception of - ``--test-command`` + Additional options for configuring the build (i.e. for CMake, not for + the build tool). Note that if this is specified, the ``--build-options`` + keyword and its arguments must be the last option given on the command + line, with the possible exception of ``--test-command``. ``--test-command`` - The test to run with the ``--build-and-test`` option. + The command to run as the test step with the ``--build-and-test`` option. + All arguments following this keyword will be assumed to be part of the + test command line, so it must be the last option given. ``--test-timeout`` The time limit in seconds diff --git a/Help/policy/CMP0073.rst b/Help/policy/CMP0073.rst new file mode 100644 index 0000000..9bfa0e9 --- /dev/null +++ b/Help/policy/CMP0073.rst @@ -0,0 +1,25 @@ +CMP0073 +------- + +Do not produce legacy ``_LIB_DEPENDS`` cache entries. + +Ancient CMake versions once used ``<tgt>_LIB_DEPENDS`` cache entries to +propagate library link dependencies. This has long been done by other +means, leaving the :command:`export_library_dependencies` command as the +only user of these values. That command has long been disallowed by +policy :policy:`CMP0033`, but the ``<tgt>_LIB_DEPENDS`` cache entries +were left for compatibility with possible non-standard uses by projects. + +CMake 3.12 and above now prefer to not produce these cache entries +at all. This policy provides compatibility with projects that have +not been updated to avoid using them. + +The ``OLD`` behavior for this policy is to set ``<tgt>_LIB_DEPENDS`` cache +entries. The ``NEW`` behavior for this policy is to not set them. + +This policy was introduced in CMake version 3.12. Use the +:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly. +Unlike most policies, CMake version |release| does *not* warn +when this policy is not set and simply uses ``OLD`` behavior. + +.. include:: DEPRECATED.txt diff --git a/Help/policy/CMP0074.rst b/Help/policy/CMP0074.rst new file mode 100644 index 0000000..ffac4a7 --- /dev/null +++ b/Help/policy/CMP0074.rst @@ -0,0 +1,22 @@ +CMP0074 +------- + +:command:`find_package` uses ``PackageName_ROOT`` variables. + +In CMake 3.12 and above the ``find_package(PackageName)`` command now searches +a prefix specified by a ``PackageName_ROOT`` CMake or environment variable. +Package roots are maintained as a stack so nested calls to all ``find_*`` +commands inside find modules also search the roots as prefixes. This policy +provides compatibility with projects that have not been updated to avoid using +``PackageName_ROOT`` variables for other purposes. + +The ``OLD`` behavior for this policy is to ignore ``PackageName_ROOT`` +variables. The ``NEW`` behavior for this policy is to use ``PackageName_ROOT`` +variables. + +This policy was introduced in CMake version 3.12. CMake version +|release| warns when the policy is not set and uses ``OLD`` behavior. +Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` +explicitly. + +.. include:: DEPRECATED.txt diff --git a/Help/prop_dir/TESTS.rst b/Help/prop_dir/TESTS.rst new file mode 100644 index 0000000..c6e1d88 --- /dev/null +++ b/Help/prop_dir/TESTS.rst @@ -0,0 +1,7 @@ +TESTS +----- + +List of tests. + +This read-only property holds a :ref:`;-list <CMake Language Lists>` of tests +defined so far by the :command:`add_test` command. diff --git a/Help/prop_test/PROCESSORS.rst b/Help/prop_test/PROCESSORS.rst index a1211fb..a927c10 100644 --- a/Help/prop_test/PROCESSORS.rst +++ b/Help/prop_test/PROCESSORS.rst @@ -2,6 +2,7 @@ PROCESSORS ---------- Set to specify how many process slots this test requires. +If not set, the default is ``1`` processor. Denotes the number of processors that this test will require. This is typically used for MPI tests, and should be used in conjunction with @@ -11,3 +12,5 @@ This will also be used to display a weighted test timing result in label and subproject summaries in the command line output of :manual:`ctest(1)`. The wall clock time for the test run will be multiplied by this property to give a better idea of how much cpu resource CTest allocated for the test. + +See also the :prop_test:`PROCESSOR_AFFINITY` test property. diff --git a/Help/prop_test/PROCESSOR_AFFINITY.rst b/Help/prop_test/PROCESSOR_AFFINITY.rst new file mode 100644 index 0000000..38ec179 --- /dev/null +++ b/Help/prop_test/PROCESSOR_AFFINITY.rst @@ -0,0 +1,11 @@ +PROCESSOR_AFFINITY +------------------ + +Set to a true value to ask CTest to launch the test process with CPU affinity +for a fixed set of processors. If enabled and supported for the current +platform, CTest will choose a set of processors to place in the CPU affinity +mask when launching the test process. The number of processors in the set is +determined by the :prop_test:`PROCESSORS` test property or the number of +processors available to CTest, whichever is smaller. The set of processors +chosen will be disjoint from the processors assigned to other concurrently +running tests that also have the ``PROCESSOR_AFFINITY`` property enabled. diff --git a/Help/prop_test/WORKING_DIRECTORY.rst b/Help/prop_test/WORKING_DIRECTORY.rst index 5222a19..92a0409 100644 --- a/Help/prop_test/WORKING_DIRECTORY.rst +++ b/Help/prop_test/WORKING_DIRECTORY.rst @@ -3,5 +3,7 @@ WORKING_DIRECTORY The directory from which the test executable will be called. -If this is not set it is called from the directory the test executable -is located in. +If this is not set, the test will be run with the working directory set to the +binary directory associated with where the test was created (i.e. the +:variable:`CMAKE_CURRENT_BINARY_DIR` for where :command:`add_test` was +called). diff --git a/Help/prop_tgt/EXPORT_PROPERTIES.rst b/Help/prop_tgt/EXPORT_PROPERTIES.rst new file mode 100644 index 0000000..bcf47a6 --- /dev/null +++ b/Help/prop_tgt/EXPORT_PROPERTIES.rst @@ -0,0 +1,14 @@ +EXPORT_PROPERTIES +----------------- + +List additional properties to export for a target. + +This property contains a list of property names that should be exported by +the :command:`install(EXPORT)` and :command:`export` commands. By default +only a limited number of properties are exported. This property can be used +to additionally export other properties as well. + +Properties starting with ``INTERFACE_`` or ``IMPORTED_`` are not allowed as +they are reserved for internal CMake use. + +Properties containing generator expressions are also not allowed. diff --git a/Help/prop_tgt/VS_DEBUGGER_COMMAND.rst b/Help/prop_tgt/VS_DEBUGGER_COMMAND.rst new file mode 100644 index 0000000..f898750 --- /dev/null +++ b/Help/prop_tgt/VS_DEBUGGER_COMMAND.rst @@ -0,0 +1,9 @@ +VS_DEBUGGER_COMMAND +------------------- + +Sets the local debugger command for Visual Studio C++ targets. +This is defined in ``<LocalDebuggerCommand>`` in the Visual Studio +project file. + +This property only works for Visual Studio 2010 and above; +it is ignored on other generators. diff --git a/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst b/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst index 0af85cb..fb0389e 100644 --- a/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst +++ b/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst @@ -4,3 +4,6 @@ VS_DEBUGGER_WORKING_DIRECTORY Sets the local debugger working directory for Visual Studio C++ targets. This is defined in ``<LocalDebuggerWorkingDirectory>`` in the Visual Studio project file. + +This property only works for Visual Studio 2010 and above; +it is ignored on other generators. diff --git a/Help/release/dev/0-sample-topic.rst b/Help/release/dev/0-sample-topic.rst new file mode 100644 index 0000000..e4cc01e --- /dev/null +++ b/Help/release/dev/0-sample-topic.rst @@ -0,0 +1,7 @@ +0-sample-topic +-------------- + +* This is a sample release note for the change in a topic. + Developers should add similar notes for each topic branch + making a noteworthy change. Each document should be named + and titled to match the topic name to avoid merge conflicts. diff --git a/Help/release/dev/UseSWIG-modernize-module.rst b/Help/release/dev/UseSWIG-modernize-module.rst new file mode 100644 index 0000000..925c119 --- /dev/null +++ b/Help/release/dev/UseSWIG-modernize-module.rst @@ -0,0 +1,6 @@ +UseSWIG-modernize-module +------------------------ + +* The :module:`UseSWIG` gained a whole refresh and is now more consistent with + standard CMake commands to generate libraries and is fully configurable through + properties. diff --git a/Help/release/dev/avoid-LIB_DEPENDS.rst b/Help/release/dev/avoid-LIB_DEPENDS.rst new file mode 100644 index 0000000..b89d8f9 --- /dev/null +++ b/Help/release/dev/avoid-LIB_DEPENDS.rst @@ -0,0 +1,5 @@ +avoid-LIB_DEPENDS +----------------- + +* CMake no longer produces ``<tgt>_LIB_DEPENDS`` cache entries + for library targets. See policy :policy:`CMP0073`. diff --git a/Help/release/dev/compile-options-shell.rst b/Help/release/dev/compile-options-shell.rst new file mode 100644 index 0000000..3f83e0c --- /dev/null +++ b/Help/release/dev/compile-options-shell.rst @@ -0,0 +1,6 @@ +compile-options-shell +--------------------- + +* :command:`target_compile_options` and :command:`add_compile_options` + commands gained a ``SHELL:`` prefix to specify a group of related + options using shell-like quoting. diff --git a/Help/release/dev/ctest-affinity.rst b/Help/release/dev/ctest-affinity.rst new file mode 100644 index 0000000..f4f72a5 --- /dev/null +++ b/Help/release/dev/ctest-affinity.rst @@ -0,0 +1,6 @@ +ctest-affinity +-------------- + +* A :prop_test:`PROCESSOR_AFFINITY` test property was added to request + that CTest run a test with CPU affinity for a set of processors + disjoint from other concurrently running tests with the property set. diff --git a/Help/release/dev/curl-target.rst b/Help/release/dev/curl-target.rst new file mode 100644 index 0000000..dc65f64 --- /dev/null +++ b/Help/release/dev/curl-target.rst @@ -0,0 +1,4 @@ +curl-target +----------- + +* The :module:`FindCURL` module now provides imported targets. diff --git a/Help/release/dev/directory-property-TESTS.rst b/Help/release/dev/directory-property-TESTS.rst new file mode 100644 index 0000000..9de2531 --- /dev/null +++ b/Help/release/dev/directory-property-TESTS.rst @@ -0,0 +1,5 @@ +directory-property-TESTS +------------------------ + +* The :prop_dir:`TESTS` directory property was added to hold the list of tests defined by + command :command:`add_test`. diff --git a/Help/release/dev/export-properties.rst b/Help/release/dev/export-properties.rst new file mode 100644 index 0000000..9b20799 --- /dev/null +++ b/Help/release/dev/export-properties.rst @@ -0,0 +1,6 @@ +EXPORT_PROPERTIES +----------------- + +* An :prop_tgt:`EXPORT_PROPERTIES` target property was added to specify a + custom list of target properties to include in targets exported by the + :command:`install(EXPORT)` and :command:`export` commands. diff --git a/Help/release/dev/file_cmd_touch.rst b/Help/release/dev/file_cmd_touch.rst new file mode 100644 index 0000000..b1b1e3c --- /dev/null +++ b/Help/release/dev/file_cmd_touch.rst @@ -0,0 +1,6 @@ +file_cmd_touch +------------------ + +* The :command:`file(TOUCH)` and :command:`file(TOUCH_NOCREATE)` commands + were added to expose TOUCH functionality without having to use CMake's + command-line tool mode with :command:`execute_process`. diff --git a/Help/release/dev/find-package_root-restore.rst b/Help/release/dev/find-package_root-restore.rst new file mode 100644 index 0000000..3e6b69e --- /dev/null +++ b/Help/release/dev/find-package_root-restore.rst @@ -0,0 +1,8 @@ +find-package_root-restore +------------------------- + +* The :command:`find_package` command now searches a prefix specified by + a ``PackageName_ROOT`` CMake or environment variable. Package roots are + maintained as a stack so nested calls to all ``find_*`` commands inside + find modules also search the roots as prefixes. + See policy :policy:`CMP0074`. diff --git a/Help/release/dev/genex-IN_LIST-logical-operator.rst b/Help/release/dev/genex-IN_LIST-logical-operator.rst new file mode 100644 index 0000000..28fa7ce --- /dev/null +++ b/Help/release/dev/genex-IN_LIST-logical-operator.rst @@ -0,0 +1,5 @@ +genex-IN_LIST-logical-operator +------------------------------ + +* A new ``$<IN_LIST:...>`` :manual:`generator expression <cmake-generator-expressions(7)>` + has been added. diff --git a/Help/release/dev/genex-TARGET_EXISTS.rst b/Help/release/dev/genex-TARGET_EXISTS.rst new file mode 100644 index 0000000..f305522 --- /dev/null +++ b/Help/release/dev/genex-TARGET_EXISTS.rst @@ -0,0 +1,6 @@ +genex-TARGET_EXISTS +------------------- + +* A new ``$<TARGET_EXISTS:...>`` + :manual:`generator expression <cmake-generator-expressions(7)>` + has been added. diff --git a/Help/release/dev/libxml2-target.rst b/Help/release/dev/libxml2-target.rst new file mode 100644 index 0000000..f9933d7 --- /dev/null +++ b/Help/release/dev/libxml2-target.rst @@ -0,0 +1,4 @@ +libxml2-target +-------------- + +* The :module:`FindLibXml2` module now provides imported targets. diff --git a/Help/release/dev/object-library-linking.rst b/Help/release/dev/object-library-linking.rst new file mode 100644 index 0000000..131430f --- /dev/null +++ b/Help/release/dev/object-library-linking.rst @@ -0,0 +1,6 @@ +object-library-linking +---------------------- + +* The :command:`target_link_libraries` command now supports + :ref:`Object Libraries`. Linking to an object library uses its object + files in direct dependents and also propagates usage requirements. diff --git a/Help/release/dev/project-homepage.rst b/Help/release/dev/project-homepage.rst new file mode 100644 index 0000000..25799a4 --- /dev/null +++ b/Help/release/dev/project-homepage.rst @@ -0,0 +1,7 @@ +project-homepage +---------------- + +* The :command:`project` command learned an optional ``HOMEPAGE_URL`` + parameter which has the effect of setting variables like + :variable:`PROJECT_HOMEPAGE_URL`, :variable:`<PROJECT-NAME>_HOMEPAGE_URL` + and :variable:`CMAKE_PROJECT_HOMEPAGE_URL`. diff --git a/Help/release/dev/string-join.rst b/Help/release/dev/string-join.rst new file mode 100644 index 0000000..5cca711 --- /dev/null +++ b/Help/release/dev/string-join.rst @@ -0,0 +1,5 @@ +string-join +----------- + +* The :command:`string` command learned a ``JOIN`` sub-command + to concatenate input strings separated by a glue string. diff --git a/Help/release/dev/variable-CMAKE_SUPPRESS_REGENERATION.rst b/Help/release/dev/variable-CMAKE_SUPPRESS_REGENERATION.rst new file mode 100644 index 0000000..dfe678c --- /dev/null +++ b/Help/release/dev/variable-CMAKE_SUPPRESS_REGENERATION.rst @@ -0,0 +1,6 @@ +variable-CMAKE_SUPPRESS_REGENERATION +------------------------------------ + +* The :variable:`CMAKE_SUPPRESS_REGENERATION` variable was extended to support the + :generator:`Ninja` and :ref:`Makefile Generators`. +* The :variable:`CMAKE_SUPPRESS_REGENERATION` variable is now documented. diff --git a/Help/release/dev/vs-debugger-config.rst b/Help/release/dev/vs-debugger-config.rst new file mode 100644 index 0000000..bddae0c --- /dev/null +++ b/Help/release/dev/vs-debugger-config.rst @@ -0,0 +1,6 @@ +vs-debugger-configuration +------------------------- + +* For the :ref:`Visual Studio Generators` for VS 2010 and above + the debugging command line can be set using a new + :prop_tgt:`VS_DEBUGGER_COMMAND` target property. diff --git a/Help/release/index.rst b/Help/release/index.rst index 7375faf..552922e 100644 --- a/Help/release/index.rst +++ b/Help/release/index.rst @@ -7,6 +7,8 @@ CMake Release Notes This file should include the adjacent "dev.txt" file in development versions but not in release versions. +.. include:: dev.txt + Releases ======== diff --git a/Help/variable/CMAKE_PROJECT_DESCRIPTION.rst b/Help/variable/CMAKE_PROJECT_DESCRIPTION.rst index f1911ec..51b0592 100644 --- a/Help/variable/CMAKE_PROJECT_DESCRIPTION.rst +++ b/Help/variable/CMAKE_PROJECT_DESCRIPTION.rst @@ -1,7 +1,35 @@ CMAKE_PROJECT_DESCRIPTION ------------------------- -The description of the current project. +The description of the top level project. -This specifies description of the current project from the closest inherited -:command:`project` command. +This variable holds the description of the project as specified in the top +level CMakeLists.txt file by a :command:`project` command. In the event that +the top level CMakeLists.txt contains multiple :command:`project` calls, +the most recently called one from that top level CMakeLists.txt will determine +the value that ``CMAKE_PROJECT_DESCRIPTION`` contains. For example, consider +the following top level CMakeLists.txt: + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.0) + project(First DESCRIPTION "I am First") + project(Second DESCRIPTION "I am Second") + add_subdirectory(sub) + project(Third DESCRIPTION "I am Third") + +And ``sub/CMakeLists.txt`` with the following contents: + +.. code-block:: cmake + + project(SubProj DESCRIPTION "I am SubProj") + message("CMAKE_PROJECT_DESCRIPTION = ${CMAKE_PROJECT_DESCRIPTION}") + +The most recently seen :command:`project` command from the top level +CMakeLists.txt would be ``project(Second ...)``, so this will print:: + + CMAKE_PROJECT_DESCRIPTION = I am Second + +To obtain the description from the most recent call to :command:`project` in +the current directory scope or above, see the :variable:`PROJECT_DESCRIPTION` +variable. diff --git a/Help/variable/CMAKE_PROJECT_HOMEPAGE_URL.rst b/Help/variable/CMAKE_PROJECT_HOMEPAGE_URL.rst new file mode 100644 index 0000000..ee0bf7c --- /dev/null +++ b/Help/variable/CMAKE_PROJECT_HOMEPAGE_URL.rst @@ -0,0 +1,35 @@ +CMAKE_PROJECT_HOMEPAGE_URL +-------------------------- + +The homepage URL of the top level project. + +This variable holds the homepage URL of the project as specified in the top +level CMakeLists.txt file by a :command:`project` command. In the event that +the top level CMakeLists.txt contains multiple :command:`project` calls, +the most recently called one from that top level CMakeLists.txt will determine +the value that ``CMAKE_PROJECT_HOMEPAGE_URL`` contains. For example, consider +the following top level CMakeLists.txt: + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.0) + project(First HOMEPAGE_URL "http://first.example.com") + project(Second HOMEPAGE_URL "http://second.example.com") + add_subdirectory(sub) + project(Third HOMEPAGE_URL "http://third.example.com") + +And ``sub/CMakeLists.txt`` with the following contents: + +.. code-block:: cmake + + project(SubProj HOMEPAGE_URL "http://subproj.example.com") + message("CMAKE_PROJECT_HOMEPAGE_URL = ${CMAKE_PROJECT_HOMEPAGE_URL}") + +The most recently seen :command:`project` command from the top level +CMakeLists.txt would be ``project(Second ...)``, so this will print:: + + CMAKE_PROJECT_HOMEPAGE_URL = http://second.example.com + +To obtain the homepage URL from the most recent call to :command:`project` in +the current directory scope or above, see the :variable:`PROJECT_HOMEPAGE_URL` +variable. diff --git a/Help/variable/CMAKE_PROJECT_NAME.rst b/Help/variable/CMAKE_PROJECT_NAME.rst index 431e9f3..94b8dba 100644 --- a/Help/variable/CMAKE_PROJECT_NAME.rst +++ b/Help/variable/CMAKE_PROJECT_NAME.rst @@ -1,7 +1,35 @@ CMAKE_PROJECT_NAME ------------------ -The name of the current project. +The name of the top level project. -This specifies name of the current project from the closest inherited -:command:`project` command. +This variable holds the name of the project as specified in the top +level CMakeLists.txt file by a :command:`project` command. In the event that +the top level CMakeLists.txt contains multiple :command:`project` calls, +the most recently called one from that top level CMakeLists.txt will determine +the name that ``CMAKE_PROJECT_NAME`` contains. For example, consider +the following top level CMakeLists.txt: + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.0) + project(First) + project(Second) + add_subdirectory(sub) + project(Third) + +And ``sub/CMakeLists.txt`` with the following contents: + +.. code-block:: cmake + + project(SubProj) + message("CMAKE_PROJECT_NAME = ${CMAKE_PROJECT_NAME}") + +The most recently seen :command:`project` command from the top level +CMakeLists.txt would be ``project(Second)``, so this will print:: + + CMAKE_PROJECT_NAME = Second + +To obtain the name from the most recent call to :command:`project` in +the current directory scope or above, see the :variable:`PROJECT_NAME` +variable. diff --git a/Help/variable/CMAKE_SUPPRESS_REGENERATION.rst b/Help/variable/CMAKE_SUPPRESS_REGENERATION.rst new file mode 100644 index 0000000..ed47e1a --- /dev/null +++ b/Help/variable/CMAKE_SUPPRESS_REGENERATION.rst @@ -0,0 +1,11 @@ +CMAKE_SUPPRESS_REGENERATION +--------------------------- + +If CMAKE_SUPPRESS_REGENERATION is ``OFF``, which is default, then CMake adds a +special target on which all other targets depend that checks the build system +and optionally re-runs CMake to regenerate the build system when the target +specification source changes. + +If this variable evaluates to ``ON`` at the end of the top-level +``CMakeLists.txt`` file, CMake will not add the regeneration target to the +build system or perform any build system checks. diff --git a/Help/variable/PROJECT-NAME_DESCRIPTION.rst b/Help/variable/PROJECT-NAME_DESCRIPTION.rst new file mode 100644 index 0000000..2b88b1a --- /dev/null +++ b/Help/variable/PROJECT-NAME_DESCRIPTION.rst @@ -0,0 +1,5 @@ +<PROJECT-NAME>_DESCRIPTION +-------------------------- + +Value given to the ``DESCRIPTION`` option of the most recent call to the +:command:`project` command with project name ``<PROJECT-NAME>``, if any. diff --git a/Help/variable/PROJECT-NAME_HOMEPAGE_URL.rst b/Help/variable/PROJECT-NAME_HOMEPAGE_URL.rst new file mode 100644 index 0000000..22cc304 --- /dev/null +++ b/Help/variable/PROJECT-NAME_HOMEPAGE_URL.rst @@ -0,0 +1,5 @@ +<PROJECT-NAME>_HOMEPAGE_URL +--------------------------- + +Value given to the ``HOMEPAGE_URL`` option of the most recent call to the +:command:`project` command with project name ``<PROJECT-NAME>``, if any. diff --git a/Help/variable/PROJECT_DESCRIPTION.rst b/Help/variable/PROJECT_DESCRIPTION.rst index 05ede8f..2833e11 100644 --- a/Help/variable/PROJECT_DESCRIPTION.rst +++ b/Help/variable/PROJECT_DESCRIPTION.rst @@ -3,4 +3,7 @@ PROJECT_DESCRIPTION Short project description given to the project command. -This is the description given to the most recent :command:`project` command. +This is the description given to the most recently called :command:`project` +command in the current directory scope or above. To obtain the description +of the top level project, see the :variable:`CMAKE_PROJECT_DESCRIPTION` +variable. diff --git a/Help/variable/PROJECT_HOMEPAGE_URL.rst b/Help/variable/PROJECT_HOMEPAGE_URL.rst new file mode 100644 index 0000000..754c9e8 --- /dev/null +++ b/Help/variable/PROJECT_HOMEPAGE_URL.rst @@ -0,0 +1,9 @@ +PROJECT_HOMEPAGE_URL +-------------------- + +The homepage URL of the project. + +This is the homepage URL given to the most recently called :command:`project` +command in the current directory scope or above. To obtain the homepage URL +of the top level project, see the :variable:`CMAKE_PROJECT_HOMEPAGE_URL` +variable. diff --git a/Help/variable/PROJECT_NAME.rst b/Help/variable/PROJECT_NAME.rst index 61aa8bc..672680a 100644 --- a/Help/variable/PROJECT_NAME.rst +++ b/Help/variable/PROJECT_NAME.rst @@ -3,4 +3,6 @@ PROJECT_NAME Name of the project given to the project command. -This is the name given to the most recent :command:`project` command. +This is the name given to the most recently called :command:`project` +command in the current directory scope or above. To obtain the name of +the top level project, see the :variable:`CMAKE_PROJECT_NAME` variable. diff --git a/Modules/CMakeDetermineFortranCompiler.cmake b/Modules/CMakeDetermineFortranCompiler.cmake index cf502f6..5ddd64f 100644 --- a/Modules/CMakeDetermineFortranCompiler.cmake +++ b/Modules/CMakeDetermineFortranCompiler.cmake @@ -66,12 +66,20 @@ else() # The order is 95 or newer compilers first, then 90, # then 77 or older compilers, gnu is always last in the group, # so if you paid for a compiler it is picked by default. - set(CMAKE_Fortran_COMPILER_LIST - ftn - ifort ifc af95 af90 efc f95 pathf2003 pathf95 pgf95 pgfortran lf95 xlf95 - fort flang gfortran gfortran-4 g95 f90 pathf90 pgf90 xlf90 epcf90 fort77 - frt pgf77 xlf fl32 af77 g77 f77 nag - ) + if(CMAKE_HOST_WIN32) + set(CMAKE_Fortran_COMPILER_LIST + ifort pgf95 pgfortran lf95 fort + flang gfortran gfortran-4 g95 f90 pgf90 + pgf77 g77 f77 nag + ) + else() + set(CMAKE_Fortran_COMPILER_LIST + ftn + ifort ifc efc pgf95 pgfortran lf95 xlf95 fort + flang gfortran gfortran-4 g95 f90 pgf90 + frt pgf77 xlf g77 f77 nag + ) + endif() # Vendor-specific compiler names. set(_Fortran_COMPILER_NAMES_GNU gfortran gfortran-4 g95 g77) diff --git a/Modules/CMakeFindBinUtils.cmake b/Modules/CMakeFindBinUtils.cmake index ece0547..1b6823c 100644 --- a/Modules/CMakeFindBinUtils.cmake +++ b/Modules/CMakeFindBinUtils.cmake @@ -19,6 +19,25 @@ # on UNIX, cygwin and mingw +if(CMAKE_LINKER) + # we only get here if CMAKE_LINKER was specified using -D or a pre-made CMakeCache.txt + # (e.g. via ctest) or set in CMAKE_TOOLCHAIN_FILE + # find the linker in the PATH if necessary + get_filename_component(_CMAKE_USER_LINKER_PATH "${CMAKE_LINKER}" PATH) + if(NOT _CMAKE_USER_LINKER_PATH) + find_program(CMAKE_LINKER_WITH_PATH NAMES ${CMAKE_LINKER} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) + if(CMAKE_LINKER_WITH_PATH) + set(CMAKE_LINKER ${CMAKE_LINKER_WITH_PATH}) + get_property(_CMAKE_LINKER_CACHED CACHE CMAKE_LINKER PROPERTY TYPE) + if(_CMAKE_LINKER_CACHED) + set(CMAKE_LINKER "${CMAKE_LINKER}" CACHE STRING "Default Linker" FORCE) + endif() + unset(_CMAKE_LINKER_CACHED) + endif() + unset(CMAKE_LINKER_WITH_PATH CACHE) + endif() +endif() + # if it's the MS C/CXX compiler, search for link if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC" OR "x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xMSVC" diff --git a/Modules/CMakeTestCSharpCompiler.cmake b/Modules/CMakeTestCSharpCompiler.cmake index f3b95fd..6715c30 100644 --- a/Modules/CMakeTestCSharpCompiler.cmake +++ b/Modules/CMakeTestCSharpCompiler.cmake @@ -15,7 +15,7 @@ unset(CMAKE_CSharp_COMPILER_WORKS CACHE) set(test_compile_file "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testCSharpCompiler.cs") # This file is used by EnableLanguage in cmGlobalGenerator to -# determine that that selected C# compiler can actually compile +# determine that the selected C# compiler can actually compile # and link the most basic of programs. If not, a fatal error # is set and cmake stops processing commands and will not generate # any makefiles or projects. diff --git a/Modules/CMakeTestCUDACompiler.cmake b/Modules/CMakeTestCUDACompiler.cmake index df5ec72..f0454da 100644 --- a/Modules/CMakeTestCUDACompiler.cmake +++ b/Modules/CMakeTestCUDACompiler.cmake @@ -15,7 +15,7 @@ include(CMakeTestCompilerCommon) unset(CMAKE_CUDA_COMPILER_WORKS CACHE) # This file is used by EnableLanguage in cmGlobalGenerator to -# determine that that selected cuda compiler can actually compile +# determine that the selected cuda compiler can actually compile # and link the most basic of programs. If not, a fatal error # is set and cmake stops processing commands and will not generate # any makefiles or projects. diff --git a/Modules/CMakeTestCXXCompiler.cmake b/Modules/CMakeTestCXXCompiler.cmake index 7b80dc0..e4d49ae 100644 --- a/Modules/CMakeTestCXXCompiler.cmake +++ b/Modules/CMakeTestCXXCompiler.cmake @@ -16,7 +16,7 @@ include(CMakeTestCompilerCommon) unset(CMAKE_CXX_COMPILER_WORKS CACHE) # This file is used by EnableLanguage in cmGlobalGenerator to -# determine that that selected C++ compiler can actually compile +# determine that the selected C++ compiler can actually compile # and link the most basic of programs. If not, a fatal error # is set and cmake stops processing commands and will not generate # any makefiles or projects. diff --git a/Modules/CMakeTestFortranCompiler.cmake b/Modules/CMakeTestFortranCompiler.cmake index 3c150a8..e9860e9 100644 --- a/Modules/CMakeTestFortranCompiler.cmake +++ b/Modules/CMakeTestFortranCompiler.cmake @@ -16,7 +16,7 @@ include(CMakeTestCompilerCommon) unset(CMAKE_Fortran_COMPILER_WORKS CACHE) # This file is used by EnableLanguage in cmGlobalGenerator to -# determine that that selected Fortran compiler can actually compile +# determine that the selected Fortran compiler can actually compile # and link the most basic of programs. If not, a fatal error # is set and cmake stops processing commands and will not generate # any makefiles or projects. diff --git a/Modules/CMakeTestJavaCompiler.cmake b/Modules/CMakeTestJavaCompiler.cmake index 23fdbdc..3c33573 100644 --- a/Modules/CMakeTestJavaCompiler.cmake +++ b/Modules/CMakeTestJavaCompiler.cmake @@ -3,7 +3,7 @@ # This file is used by EnableLanguage in cmGlobalGenerator to -# determine that that selected Fortran compiler can actually compile +# determine that the selected Fortran compiler can actually compile # and link the most basic of programs. If not, a fatal error # is set and cmake stops processing commands and will not generate # any makefiles or projects. diff --git a/Modules/CMakeTestRCCompiler.cmake b/Modules/CMakeTestRCCompiler.cmake index c510d3a..3123a6c 100644 --- a/Modules/CMakeTestRCCompiler.cmake +++ b/Modules/CMakeTestRCCompiler.cmake @@ -3,7 +3,7 @@ # This file is used by EnableLanguage in cmGlobalGenerator to -# determine that that selected RC compiler can actually compile +# determine that the selected RC compiler can actually compile # and link the most basic of programs. If not, a fatal error # is set and cmake stops processing commands and will not generate # any makefiles or projects. diff --git a/Modules/CMakeTestSwiftCompiler.cmake b/Modules/CMakeTestSwiftCompiler.cmake index bcd5c33..858c1be 100644 --- a/Modules/CMakeTestSwiftCompiler.cmake +++ b/Modules/CMakeTestSwiftCompiler.cmake @@ -16,7 +16,7 @@ include(CMakeTestCompilerCommon) unset(CMAKE_Swift_COMPILER_WORKS CACHE) # This file is used by EnableLanguage in cmGlobalGenerator to -# determine that that selected C++ compiler can actually compile +# determine that the selected C++ compiler can actually compile # and link the most basic of programs. If not, a fatal error # is set and cmake stops processing commands and will not generate # any makefiles or projects. diff --git a/Modules/CPackDeb.cmake b/Modules/CPackDeb.cmake index 35447c9..444f632 100644 --- a/Modules/CPackDeb.cmake +++ b/Modules/CPackDeb.cmake @@ -254,7 +254,7 @@ # upstream documentation or information may be found. # # * Mandatory : NO -# * Default : - +# * Default : :variable:`CMAKE_PROJECT_HOMEPAGE_URL` # # .. note:: # @@ -914,6 +914,11 @@ function(cpack_deb_prepare_package_vars) endif() endif() + # Homepage: (optional) + if(NOT CPACK_DEBIAN_PACKAGE_HOMEPAGE AND CMAKE_PROJECT_HOMEPAGE_URL) + set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "${CMAKE_PROJECT_HOMEPAGE_URL}") + endif() + # Section: (recommended) if(NOT CPACK_DEBIAN_PACKAGE_SECTION) set(CPACK_DEBIAN_PACKAGE_SECTION "devel") diff --git a/Modules/CPackFreeBSD.cmake b/Modules/CPackFreeBSD.cmake index 7fec78a..b681d4f 100644 --- a/Modules/CPackFreeBSD.cmake +++ b/Modules/CPackFreeBSD.cmake @@ -80,7 +80,8 @@ the RPM information (e.g. package license). * Mandatory: YES * Default: - - :variable:`CPACK_DEBIAN_PACKAGE_HOMEPAGE` (this may be set already + - :variable:`CMAKE_PROJECT_HOMEPAGE_URL`, or if that is not set, + :variable:`CPACK_DEBIAN_PACKAGE_HOMEPAGE` (this may be set already for Debian packaging, so we may as well re-use it). .. variable:: CPACK_FREEBSD_PACKAGE_LICENSE @@ -208,6 +209,7 @@ _cpack_freebsd_fallback_var("CPACK_FREEBSD_PACKAGE_DESCRIPTION" # There's really only one homepage for a project, so # re-use the Debian setting if it's there. _cpack_freebsd_fallback_var("CPACK_FREEBSD_PACKAGE_WWW" + "CMAKE_PROJECT_HOMEPAGE_URL" "CPACK_DEBIAN_PACKAGE_HOMEPAGE" "_cpack_freebsd_fallback_www" ) diff --git a/Modules/CPackNSIS.cmake b/Modules/CPackNSIS.cmake index 18d1871..5bc4395 100644 --- a/Modules/CPackNSIS.cmake +++ b/Modules/CPackNSIS.cmake @@ -126,7 +126,7 @@ # .. variable:: CPACK_NSIS_MENU_LINKS # # Specify links in [application] menu. This should contain a list of pair -# "link" "link name". The link may be an URL or a path relative to +# "link" "link name". The link may be a URL or a path relative to # installation prefix. Like:: # # set(CPACK_NSIS_MENU_LINKS diff --git a/Modules/CPackRPM.cmake b/Modules/CPackRPM.cmake index bb5181f..87385de 100644 --- a/Modules/CPackRPM.cmake +++ b/Modules/CPackRPM.cmake @@ -191,7 +191,7 @@ # The projects URL. # # * Mandatory : NO -# * Default : - +# * Default : :variable:`CMAKE_PROJECT_HOMEPAGE_URL` # # .. variable:: CPACK_RPM_PACKAGE_DESCRIPTION # CPACK_RPM_<component>_PACKAGE_DESCRIPTION @@ -1787,6 +1787,10 @@ function(cpack_rpm_generate_package) endif() endif() + if(NOT CPACK_RPM_PACKAGE_URL AND CMAKE_PROJECT_HOMEPAGE_URL) + set(CPACK_RPM_PACKAGE_URL "${CMAKE_PROJECT_HOMEPAGE_URL}") + endif() + # CPACK_RPM_PACKAGE_NAME (mandatory) if(NOT CPACK_RPM_PACKAGE_NAME) string(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_RPM_PACKAGE_NAME) @@ -1984,7 +1988,7 @@ function(cpack_rpm_generate_package) endif() if(DEFINED CPACK_RPM_PACKAGE_${_RPM_SPEC_HEADER}) - # Prefix can be replaced by Prefixes but the old version stil works so we'll ignore it for now + # Prefix can be replaced by Prefixes but the old version still works so we'll ignore it for now # Requires* is a special case because it gets transformed to Requires(pre/post/preun/postun) # Auto* is a special case because the tags can not be queried by querytags rpmbuild flag set(special_case_tags_ PREFIX REQUIRES_PRE REQUIRES_POST REQUIRES_PREUN REQUIRES_POSTUN AUTOPROV AUTOREQ AUTOREQPROV) diff --git a/Modules/CheckCSourceRuns.cmake b/Modules/CheckCSourceRuns.cmake index fa51346..7eb050c 100644 --- a/Modules/CheckCSourceRuns.cmake +++ b/Modules/CheckCSourceRuns.cmake @@ -92,7 +92,8 @@ macro(CHECK_C_SOURCE_RUNS SOURCE VAR) CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH} "${CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}" - COMPILE_OUTPUT_VARIABLE OUTPUT) + COMPILE_OUTPUT_VARIABLE OUTPUT + RUN_OUTPUT_VARIABLE RUN_OUTPUT) # if it did not compile make the return value fail code of 1 if(NOT ${VAR}_COMPILED) set(${VAR}_EXITCODE 1) @@ -104,8 +105,10 @@ macro(CHECK_C_SOURCE_RUNS SOURCE VAR) message(STATUS "Performing Test ${VAR} - Success") endif() file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "Performing C SOURCE FILE Test ${VAR} succeeded with the following output:\n" + "Performing C SOURCE FILE Test ${VAR} succeeded with the following compile output:\n" "${OUTPUT}\n" + "...and run output:\n" + "${RUN_OUTPUT}\n" "Return value: ${${VAR}}\n" "Source file was:\n${SOURCE}\n") else() @@ -119,8 +122,10 @@ macro(CHECK_C_SOURCE_RUNS SOURCE VAR) message(STATUS "Performing Test ${VAR} - Failed") endif() file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "Performing C SOURCE FILE Test ${VAR} failed with the following output:\n" + "Performing C SOURCE FILE Test ${VAR} failed with the following compile output:\n" "${OUTPUT}\n" + "...and run output:\n" + "${RUN_OUTPUT}\n" "Return value: ${${VAR}_EXITCODE}\n" "Source file was:\n${SOURCE}\n") diff --git a/Modules/ExternalData.cmake b/Modules/ExternalData.cmake index 7331fb2..e5dbcd9 100644 --- a/Modules/ExternalData.cmake +++ b/Modules/ExternalData.cmake @@ -1133,7 +1133,7 @@ if("${ExternalData_ACTION}" STREQUAL "fetch") if(file_up_to_date) # Touch the file to convince the build system it is up to date. - execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${file}") + file(TOUCH "${file}") else() _ExternalData_link_or_copy("${obj}" "${file}") endif() diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index 0a31ac2..119fc13 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -175,7 +175,7 @@ # -- Same as CUDA_ADD_EXECUTABLE except that a library is created. # # CUDA_BUILD_CLEAN_TARGET() -# -- Creates a convience target that deletes all the dependency files +# -- Creates a convenience target that deletes all the dependency files # generated. You should make clean after running this target to ensure the # dependency files get regenerated. # @@ -1564,7 +1564,7 @@ macro(CUDA_WRAP_SRCS cuda_target format generated_files) # Bring in the dependencies. Creates a variable CUDA_NVCC_DEPEND ####### cuda_include_nvcc_dependencies(${cmake_dependency_file}) - # Convience string for output ########################################### + # Convenience string for output ######################################### if(CUDA_BUILD_EMULATION) set(cuda_build_type "Emulation") else() @@ -1975,9 +1975,9 @@ endmacro() ############################################################################### ############################################################################### macro(CUDA_BUILD_CLEAN_TARGET) - # Call this after you add all your CUDA targets, and you will get a convience - # target. You should also make clean after running this target to get the - # build system to generate all the code again. + # Call this after you add all your CUDA targets, and you will get a + # convenience target. You should also make clean after running this target + # to get the build system to generate all the code again. set(cuda_clean_target_name clean_cuda_depends) if (CMAKE_GENERATOR MATCHES "Visual Studio") diff --git a/Modules/FindCURL.cmake b/Modules/FindCURL.cmake index f4bcc36..e66ae92 100644 --- a/Modules/FindCURL.cmake +++ b/Modules/FindCURL.cmake @@ -5,16 +5,30 @@ # FindCURL # -------- # -# Find curl -# # Find the native CURL headers and libraries. # -# :: +# IMPORTED Targets +# ^^^^^^^^^^^^^^^^ +# +# This module defines :prop_tgt:`IMPORTED` target ``CURL::CURL``, if +# curl has been found. +# +# Result Variables +# ^^^^^^^^^^^^^^^^ +# +# This module defines the following variables: # -# CURL_INCLUDE_DIRS - where to find curl/curl.h, etc. -# CURL_LIBRARIES - List of libraries when using curl. -# CURL_FOUND - True if curl found. -# CURL_VERSION_STRING - the version of curl found (since CMake 2.8.8) +# ``CURL_FOUND`` +# True if curl found. +# +# ``CURL_INCLUDE_DIRS`` +# where to find curl/curl.h, etc. +# +# ``CURL_LIBRARIES`` +# List of libraries when using curl. +# +# ``CURL_VERSION_STRING`` +# The version of curl found. # Look for the header file. find_path(CURL_INCLUDE_DIR NAMES curl/curl.h) @@ -52,4 +66,10 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(CURL if(CURL_FOUND) set(CURL_LIBRARIES ${CURL_LIBRARY}) set(CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIR}) + + if(NOT TARGET CURL::CURL) + add_library(CURL::CURL UNKNOWN IMPORTED) + set_target_properties(CURL::CURL PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CURL_INCLUDE_DIRS}") + set_property(TARGET CURL::CURL APPEND PROPERTY IMPORTED_LOCATION "${CURL_LIBRARY}") + endif() endif() diff --git a/Modules/FindGDAL.cmake b/Modules/FindGDAL.cmake index 2b940b0..ff2976e 100644 --- a/Modules/FindGDAL.cmake +++ b/Modules/FindGDAL.cmake @@ -66,11 +66,49 @@ if(UNIX) if(GDAL_CONFIG) exec_program(${GDAL_CONFIG} ARGS --libs OUTPUT_VARIABLE GDAL_CONFIG_LIBS) + if(GDAL_CONFIG_LIBS) - string(REGEX MATCHALL "-l[^ ]+" _gdal_dashl ${GDAL_CONFIG_LIBS}) - string(REPLACE "-l" "" _gdal_lib "${_gdal_dashl}") - string(REGEX MATCHALL "-L[^ ]+" _gdal_dashL ${GDAL_CONFIG_LIBS}) - string(REPLACE "-L" "" _gdal_libpath "${_gdal_dashL}") + # treat the output as a command line and split it up + separate_arguments(args NATIVE_COMMAND "${GDAL_CONFIG_LIBS}") + + # only consider libraries whose name matches this pattern + set(name_pattern "[gG][dD][aA][lL]") + + # consider each entry as a possible library path, name, or parent directory + foreach(arg IN LISTS args) + # library name + if("${arg}" MATCHES "^-l(.*)$") + set(lib "${CMAKE_MATCH_1}") + + # only consider libraries whose name matches the expected pattern + if("${lib}" MATCHES "${name_pattern}") + list(APPEND _gdal_lib "${lib}") + endif() + # library search path + elseif("${arg}" MATCHES "^-L(.*)$") + list(APPEND _gdal_libpath "${CMAKE_MATCH_1}") + # assume this is a full path to a library + elseif(IS_ABSOLUTE "${arg}" AND EXISTS "${arg}") + # extract the file name + get_filename_component(lib "${arg}" NAME) + + # only consider libraries whose name matches the expected pattern + if(NOT "${lib}" MATCHES "${name_pattern}") + continue() + endif() + + # extract the file directory + get_filename_component(dir "${arg}" DIRECTORY) + + # remove library prefixes/suffixes + string(REGEX REPLACE "^(${CMAKE_SHARED_LIBRARY_PREFIX}|${CMAKE_STATIC_LIBRARY_PREFIX})" "" lib "${lib}") + string(REGEX REPLACE "(${CMAKE_SHARED_LIBRARY_SUFFIX}|${CMAKE_STATIC_LIBRARY_SUFFIX})$" "" lib "${lib}") + + # use the file name and directory as hints + list(APPEND _gdal_libpath "${dir}") + list(APPEND _gdal_lib "${lib}") + endif() + endforeach() endif() endif() endif() diff --git a/Modules/FindJava.cmake b/Modules/FindJava.cmake index e3f5af6..c56c197 100644 --- a/Modules/FindJava.cmake +++ b/Modules/FindJava.cmake @@ -18,7 +18,7 @@ # :: # # Runtime = User just want to execute some Java byte-compiled -# Development = Development tools (java, javac, javah and javadoc), includes Runtime component +# Development = Development tools (java, javac, javah, jar and javadoc), includes Runtime component # IdlJ = idl compiler for Java # JarSigner = signer tool for jar # @@ -237,16 +237,16 @@ if(Java_FIND_COMPONENTS) endif() elseif(component STREQUAL "Development") list(APPEND _JAVA_REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAVAC_EXECUTABLE - Java_JAVADOC_EXECUTABLE) + Java_JAR_EXECUTABLE Java_JAVADOC_EXECUTABLE) if(Java_VERSION VERSION_LESS "1.10") list(APPEND _JAVA_REQUIRED_VARS Java_JAVAH_EXECUTABLE) if(Java_JAVA_EXECUTABLE AND Java_JAVAC_EXECUTABLE - AND Java_JAVAH_EXECUTABLE AND Java_JAVADOC_EXECUTABLE) + AND Java_JAVAH_EXECUTABLE AND Java_JAR_EXECUTABLE AND Java_JAVADOC_EXECUTABLE) set(Java_Development_FOUND TRUE) endif() else() if(Java_JAVA_EXECUTABLE AND Java_JAVAC_EXECUTABLE - AND Java_JAVADOC_EXECUTABLE) + AND Java_JAR_EXECUTABLE AND Java_JAVADOC_EXECUTABLE) set(Java_Development_FOUND TRUE) endif() endif() diff --git a/Modules/FindLibXml2.cmake b/Modules/FindLibXml2.cmake index 8ac2980..615de49 100644 --- a/Modules/FindLibXml2.cmake +++ b/Modules/FindLibXml2.cmake @@ -7,6 +7,12 @@ # # Find the XML processing library (libxml2). # +# IMPORTED Targets +# ^^^^^^^^^^^^^^^^ +# +# This module defines :prop_tgt:`IMPORTED` target ``LibXml2::LibXml2``, if +# libxml2 has been found. +# # Result variables # ^^^^^^^^^^^^^^^^ # @@ -87,3 +93,9 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2 VERSION_VAR LIBXML2_VERSION_STRING) mark_as_advanced(LIBXML2_INCLUDE_DIR LIBXML2_LIBRARY LIBXML2_XMLLINT_EXECUTABLE) + +if(LibXml2_FOUND AND NOT TARGET LibXml2::LibXml2) + add_library(LibXml2::LibXml2 UNKNOWN IMPORTED) + set_target_properties(LibXml2::LibXml2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBXML2_INCLUDE_DIRS}") + set_property(TARGET LibXml2::LibXml2 APPEND PROPERTY IMPORTED_LOCATION "${LIBXML2_LIBRARY}") +endif() diff --git a/Modules/FindLua.cmake b/Modules/FindLua.cmake index b59b9b3..7eba206 100644 --- a/Modules/FindLua.cmake +++ b/Modules/FindLua.cmake @@ -122,6 +122,7 @@ endif () if (NOT LUA_VERSION_STRING) foreach (subdir IN LISTS _lua_include_subdirs) unset(LUA_INCLUDE_PREFIX CACHE) + unset(LUA_INCLUDE_PREFIX) find_path(LUA_INCLUDE_PREFIX ${subdir}/lua.h HINTS ENV LUA_DIR diff --git a/Modules/FindOpenMP.cmake b/Modules/FindOpenMP.cmake index ced092e..e252ba5 100644 --- a/Modules/FindOpenMP.cmake +++ b/Modules/FindOpenMP.cmake @@ -85,6 +85,7 @@ function(_OPENMP_FLAG_CANDIDATES LANG) set(OMP_FLAG_GNU "-fopenmp") set(OMP_FLAG_Clang "-fopenmp=libomp" "-fopenmp=libiomp5" "-fopenmp") + set(OMP_FLAG_AppleClang "-Xclang -fopenmp") set(OMP_FLAG_HP "+Oopenmp") if(WIN32) set(OMP_FLAG_Intel "-Qopenmp") @@ -125,6 +126,7 @@ set(OpenMP_C_CXX_TEST_SOURCE #include <omp.h> int main() { #ifdef _OPENMP + int n = omp_get_max_threads(); return 0; #else breaks_on_purpose @@ -163,7 +165,7 @@ function(_OPENMP_WRITE_SOURCE_FILE LANG SRC_FILE_CONTENT_VAR SRC_FILE_NAME SRC_F set(${SRC_FILE_FULLPATH} "${SRC_FILE}" PARENT_SCOPE) endfunction() -include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseImplicitLinkInfo.cmake) function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR) _OPENMP_FLAG_CANDIDATES("${LANG}") @@ -255,6 +257,28 @@ function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR) endif() endif() break() + elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "AppleClang" + AND CMAKE_${LANG}_COMPILER_VERSION VERSION_GREATER_EQUAL "7.0") + + # Check for separate OpenMP library on AppleClang 7+ + find_library(OpenMP_libomp_LIBRARY + NAMES omp gomp iomp5 + HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES} + ) + mark_as_advanced(OpenMP_libomp_LIBRARY) + + if(OpenMP_libomp_LIBRARY) + try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC} + CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}" + LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY} + OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT + ) + if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}) + set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE) + set("${OPENMP_LIB_NAMES_VAR}" "libomp" PARENT_SCOPE) + break() + endif() + endif() endif() set("${OPENMP_LIB_NAMES_VAR}" "NOTFOUND" PARENT_SCOPE) set("${OPENMP_FLAG_VAR}" "NOTFOUND" PARENT_SCOPE) @@ -423,6 +447,8 @@ endif() unset(_OpenMP_MIN_VERSION) +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) + foreach(LANG IN LISTS OpenMP_FINDLIST) if(CMAKE_${LANG}_COMPILER_LOADED) if (NOT OpenMP_${LANG}_SPEC_DATE AND OpenMP_${LANG}_FLAGS) @@ -432,8 +458,6 @@ foreach(LANG IN LISTS OpenMP_FINDLIST) _OPENMP_SET_VERSION_BY_SPEC_DATE("${LANG}") endif() - include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) - set(OpenMP_${LANG}_FIND_QUIETLY ${OpenMP_FIND_QUIETLY}) set(OpenMP_${LANG}_FIND_REQUIRED ${OpenMP_FIND_REQUIRED}) set(OpenMP_${LANG}_FIND_VERSION ${OpenMP_FIND_VERSION}) diff --git a/Modules/FindZLIB.cmake b/Modules/FindZLIB.cmake index 4065999..a5c04ac 100644 --- a/Modules/FindZLIB.cmake +++ b/Modules/FindZLIB.cmake @@ -75,8 +75,8 @@ endforeach() # Allow ZLIB_LIBRARY to be set manually, as the location of the zlib library if(NOT ZLIB_LIBRARY) foreach(search ${_ZLIB_SEARCHES}) - find_library(ZLIB_LIBRARY_RELEASE NAMES ${ZLIB_NAMES} ${${search}} PATH_SUFFIXES lib) - find_library(ZLIB_LIBRARY_DEBUG NAMES ${ZLIB_NAMES_DEBUG} ${${search}} PATH_SUFFIXES lib) + find_library(ZLIB_LIBRARY_RELEASE NAMES ${ZLIB_NAMES} NAMES_PER_DIR ${${search}} PATH_SUFFIXES lib) + find_library(ZLIB_LIBRARY_DEBUG NAMES ${ZLIB_NAMES_DEBUG} NAMES_PER_DIR ${${search}} PATH_SUFFIXES lib) endforeach() include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake) diff --git a/Modules/FindwxWidgets.cmake b/Modules/FindwxWidgets.cmake index e21ec38..965948e 100644 --- a/Modules/FindwxWidgets.cmake +++ b/Modules/FindwxWidgets.cmake @@ -837,7 +837,7 @@ else() # extract linkdirs (-L) for rpath (i.e., LINK_DIRECTORIES) string(REGEX MATCHALL "-L[^;]+" wxWidgets_LIBRARY_DIRS "${wxWidgets_LIBRARIES}") - string(REPLACE "-L" "" + string(REGEX REPLACE "-L([^;]+)" "\\1" wxWidgets_LIBRARY_DIRS "${wxWidgets_LIBRARY_DIRS}") DBG_MSG_V("wxWidgets_LIBRARIES=${wxWidgets_LIBRARIES}") diff --git a/Modules/GenerateExportHeader.cmake b/Modules/GenerateExportHeader.cmake index 17a3357..e6dcd00 100644 --- a/Modules/GenerateExportHeader.cmake +++ b/Modules/GenerateExportHeader.cmake @@ -185,6 +185,7 @@ # :prop_tgt:`CXX_VISIBILITY_PRESET <<LANG>_VISIBILITY_PRESET>` and # :prop_tgt:`VISIBILITY_INLINES_HIDDEN` instead. +include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) # TODO: Install this macro separately? @@ -194,6 +195,13 @@ macro(_check_cxx_compiler_attribute _ATTRIBUTE _RESULT) ) endmacro() +# TODO: Install this macro separately? +macro(_check_c_compiler_attribute _ATTRIBUTE _RESULT) + check_c_source_compiles("${_ATTRIBUTE} int somefunc() { return 0; } + int main() { return somefunc();}" ${_RESULT} + ) +endmacro() + macro(_test_compiler_hidden_visibility) if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.2") @@ -213,9 +221,15 @@ macro(_test_compiler_hidden_visibility) AND NOT CMAKE_CXX_COMPILER_ID MATCHES XL AND NOT CMAKE_CXX_COMPILER_ID MATCHES PGI AND NOT CMAKE_CXX_COMPILER_ID MATCHES Watcom) - check_cxx_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY) - check_cxx_compiler_flag(-fvisibility-inlines-hidden - COMPILER_HAS_HIDDEN_INLINE_VISIBILITY) + if (CMAKE_CXX_COMPILER_LOADED) + check_cxx_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY) + check_cxx_compiler_flag(-fvisibility-inlines-hidden + COMPILER_HAS_HIDDEN_INLINE_VISIBILITY) + else() + check_c_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY) + check_c_compiler_flag(-fvisibility-inlines-hidden + COMPILER_HAS_HIDDEN_INLINE_VISIBILITY) + endif() endif() endmacro() @@ -232,14 +246,27 @@ macro(_test_compiler_has_deprecated) set(COMPILER_HAS_DEPRECATED "" CACHE INTERNAL "Compiler support for a deprecated attribute") else() - _check_cxx_compiler_attribute("__attribute__((__deprecated__))" - COMPILER_HAS_DEPRECATED_ATTR) - if(COMPILER_HAS_DEPRECATED_ATTR) - set(COMPILER_HAS_DEPRECATED "${COMPILER_HAS_DEPRECATED_ATTR}" - CACHE INTERNAL "Compiler support for a deprecated attribute") + if (CMAKE_CXX_COMPILER_LOADED) + _check_cxx_compiler_attribute("__attribute__((__deprecated__))" + COMPILER_HAS_DEPRECATED_ATTR) + if(COMPILER_HAS_DEPRECATED_ATTR) + set(COMPILER_HAS_DEPRECATED "${COMPILER_HAS_DEPRECATED_ATTR}" + CACHE INTERNAL "Compiler support for a deprecated attribute") + else() + _check_cxx_compiler_attribute("__declspec(deprecated)" + COMPILER_HAS_DEPRECATED) + endif() else() - _check_cxx_compiler_attribute("__declspec(deprecated)" - COMPILER_HAS_DEPRECATED) + _check_c_compiler_attribute("__attribute__((__deprecated__))" + COMPILER_HAS_DEPRECATED_ATTR) + if(COMPILER_HAS_DEPRECATED_ATTR) + set(COMPILER_HAS_DEPRECATED "${COMPILER_HAS_DEPRECATED_ATTR}" + CACHE INTERNAL "Compiler support for a deprecated attribute") + else() + _check_c_compiler_attribute("__declspec(deprecated)" + COMPILER_HAS_DEPRECATED) + endif() + endif() endif() endmacro() diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake index 0737c12..a1f54c0 100644 --- a/Modules/Platform/Windows-MSVC.cmake +++ b/Modules/Platform/Windows-MSVC.cmake @@ -293,6 +293,34 @@ macro(__windows_compiler_msvc lang) set(CMAKE_${lang}_LINK_EXECUTABLE "${_CMAKE_VS_LINK_EXE}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}") + if("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xMSVC") + set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES) + set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES) + + set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "/GL") + set(CMAKE_${lang}_LINK_OPTIONS_IPO "/INCREMENTAL:NO" "/LTCG") + string(REPLACE "<LINK_FLAGS> " "/LTCG <LINK_FLAGS> " + CMAKE_${lang}_CREATE_STATIC_LIBRARY_IPO "${CMAKE_${lang}_CREATE_STATIC_LIBRARY}") + elseif("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xClang" OR + "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xFlang") + set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES) + set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES) + + # '-flto=thin' available since Clang 3.9 and Xcode 8 + # * http://clang.llvm.org/docs/ThinLTO.html#clang-llvm + # * https://trac.macports.org/wiki/XcodeVersionInfo + set(_CMAKE_LTO_THIN TRUE) + if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.9) + set(_CMAKE_LTO_THIN FALSE) + endif() + + if(_CMAKE_LTO_THIN) + set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto=thin") + else() + set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto") + endif() + endif() + if("x${lang}" STREQUAL "xC" OR "x${lang}" STREQUAL "xCXX") if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*") diff --git a/Modules/UseJava.cmake b/Modules/UseJava.cmake index 939bd7b..7b138f5 100644 --- a/Modules/UseJava.cmake +++ b/Modules/UseJava.cmake @@ -36,7 +36,7 @@ # The default OUTPUT_DIR can also be changed by setting the variable # CMAKE_JAVA_TARGET_OUTPUT_DIR. # -# Optionaly, using option GENERATE_NATIVE_HEADERS, native header files can be generated +# Optionally, using option GENERATE_NATIVE_HEADERS, native header files can be generated # for methods declared as native. These files provide the connective glue that allow your # Java and C code to interact. An INTERFACE target will be created for an easy usage # of generated files. Sub-option DESTINATION can be used to specify output directory for diff --git a/Modules/UseSWIG.cmake b/Modules/UseSWIG.cmake index 959893f..6d35d1b 100644 --- a/Modules/UseSWIG.cmake +++ b/Modules/UseSWIG.cmake @@ -5,7 +5,7 @@ UseSWIG ------- -Defines the following macros for use with SWIG: +Defines the following command for use with SWIG: .. command:: swig_add_library @@ -14,20 +14,47 @@ Defines the following macros for use with SWIG: swig_add_library(<name> [TYPE <SHARED|MODULE|STATIC|USE_BUILD_SHARED_LIBS>] LANGUAGE <language> + [NO_PROXY] + [OUTPUT_DIR <directory>] + [OUTFILE_DIR <directory>] SOURCES <file>... - ) + ) - The variable ``SWIG_MODULE_<name>_REAL_NAME`` will be set to the name - of the swig module target library. + Targets created with command ``swig_add_library`` have the same capabilities as targets + created with command :command:`add_library`, so can be used with any command accepting a target + especially command :command:`target_link_libraries`. -.. command:: swig_link_libraries + The arguments are: - Link libraries to swig module:: + ``TYPE`` + ``SHARED``, ``MODULE`` and ``STATIC`` have same semantic as command :command:`add_library`. + if ``USE_BUILD_SHARED_LIBS`` is specified, library type will be ``STATIC`` or ``SHARED`` + based on whether the current value of the variable :variable:`BUILD_SHARED_LIBS` is ``ON``. + If none is specified, ``MODULE`` will be used. - swig_link_libraries(<name> [ libraries ]) + ``LANGUAGE`` + Specify the target language. -Source file properties on module files can be set before the invocation -of the ``swig_add_library`` macro to specify special behavior of SWIG: + ``NO_PROXY`` + Prevent the generation of the wrapper layer (swig ``-noproxy`` option). + + ``OUTPUT_DIR`` + Specify where to write the language specific files (swig ``-outdir`` option). + If not specified, variable ``CMAKE_SWIG_OUTDIR`` will be used. If none is specified, + :variable:`CMAKE_CURRENT_BINARY_DIR` is used. + + ``OUTFILE_DIR`` + Specify an output directory name where the generated source file will be placed + (swig -o option). If not specified, variable ``SWIG_OUTFILE_DIR`` will be used. + If none is specified, option ``OUTPUT_DIR`` or variable ``CMAKE_SWIG_OUTDIR`` is used. + + ``SOURCES`` + List of sources for the library. Files with extension ``.i`` will be identified as sources + for ``SWIG`` tool. Other files will be handled in the standard way. + +Source files properties on module files **must** be set before the invocation +of the ``swig_add_library`` command to specify special behavior of SWIG and ensure +generated files will receive required settings. ``CPLUSPLUS`` Call SWIG in c++ mode. For example: @@ -37,9 +64,17 @@ of the ``swig_add_library`` macro to specify special behavior of SWIG: set_property(SOURCE mymod.i PROPERTY CPLUSPLUS ON) swig_add_library(mymod LANGUAGE python SOURCES mymod.i) -``SWIG_FLAGS`` - Add custom flags to the SWIG executable. +``INCLUDE_DIRECTORIES``, ``COMPILE_DEFINITIONS`` and ``COMPILE_OPTIONS`` + Add custom flags to SWIG compiler and have same semantic as properties + :prop_sf:`INCLUDE_DIRECTORIES`, :prop_sf:`COMPILE_DEFINITIONS` and :prop_sf:`COMPILE_OPTIONS`. + +``GENERATED_INCLUDE_DIRECTORIES``, ``GENERATED_COMPILE_DEFINITIONS`` and ``GENERATED_COMPILE_OPTIONS`` + Add custom flags to the C/C++ generated source. They will fill, respectively, + properties :prop_sf:`INCLUDE_DIRECTORIES`, :prop_sf:`COMPILE_DEFINITIONS` and + :prop_sf:`COMPILE_OPTIONS` of generated C/C++ file. +``DEPENDS`` + Specify additional dependencies to the source file. ``SWIG_MODULE_NAME`` Specify the actual import name of the module in the target language. @@ -50,6 +85,34 @@ of the ``swig_add_library`` macro to specify special behavior of SWIG: set_property(SOURCE mymod.i PROPERTY SWIG_MODULE_NAME mymod_realname) +Target library properties can be set to apply same configuration to all SWIG input files. + +``SWIG_INCLUDE_DIRECTORIES``, ``SWIG_COMPILE_DEFINITIONS`` and ``SWIG_COMPILE_OPTIONS`` + These properties will be applied to all SWIG input files and have same semantic as + target properties :prop_tgt:`INCLUDE_DIRECTORIES`, :prop_tgt:`COMPILE_DEFINITIONS` and + :prop_tgt:`COMPILE_OPTIONS`. + + .. code-block:: cmake + + swig_add_library(mymod LANGUAGE python SOURCES mymod.i) + set_property(TARGET mymod PROPERTY SWIG_COMPILE_DEFINITIONS MY_DEF1 MY_DEF2) + set_property(TARGET mymod PROPERTY SWIG_COMPILE_OPTIONS -bla -blb) + +``SWIG_GENERATED_INCLUDE_DIRECTORIES``, ``SWIG_GENERATED_COMPILE_DEFINITIONS`` and ``SWIG_GENERATED_COMPILE_OPTIONS`` + These properties will populate, respectively, properties :prop_sf:`INCLUDE_DIRECTORIES`, + :prop_sf:`COMPILE_DEFINITIONS` and :prop_sf:`COMPILE_FLAGS` of all generated C/C++ files. + +``SWIG_DEPENDS`` + Add dependencies to all SWIG input files. + +``SWIG_SUPPORT_FILES`` + This output property list of wrapper files generated during SWIG compilation. + + .. code-block:: cmake + + swig_add_library(mymod LANGUAGE python SOURCES mymod.i) + get_property(support_files TARGET mymod PROPERTY SWIG_SUPPORT_FILES) + Some variables can be set to specify special behavior of SWIG: ``CMAKE_SWIG_FLAGS`` @@ -66,34 +129,56 @@ Some variables can be set to specify special behavior of SWIG: Specify extra dependencies for the generated module for ``<name>``. #]=======================================================================] + +cmake_policy (VERSION 3.11) + set(SWIG_CXX_EXTENSION "cxx") set(SWIG_EXTRA_LIBRARIES "") set(SWIG_PYTHON_EXTRA_FILE_EXTENSIONS ".py") set(SWIG_JAVA_EXTRA_FILE_EXTENSIONS ".java" "JNI.java") +## +## PRIVATE functions +## +function (__SWIG_COMPUTE_TIMESTAMP name language infile workingdir __timestamp) + get_filename_component(filename "${infile}" NAME_WE) + set(${__timestamp} + "${workingdir}/${filename}${language}.stamp" PARENT_SCOPE) + # get_filename_component(filename "${infile}" ABSOLUTE) + # string(UUID uuid NAMESPACE 9735D882-D2F8-4E1D-88C9-A0A4F1F6ECA4 + # NAME ${name}-${language}-${filename} TYPE SHA1) + # set(${__timestamp} "${workingdir}/${uuid}.stamp" PARENT_SCOPE) +endfunction() + # # For given swig module initialize variables associated with it # macro(SWIG_MODULE_INITIALIZE name language) - string(TOUPPER "${language}" swig_uppercase_language) - string(TOLOWER "${language}" swig_lowercase_language) - set(SWIG_MODULE_${name}_LANGUAGE "${swig_uppercase_language}") - set(SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG "${swig_lowercase_language}") + string(TOUPPER "${language}" SWIG_MODULE_${name}_LANGUAGE) + string(TOLOWER "${language}" SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG) - set(SWIG_MODULE_${name}_REAL_NAME "${name}") - if (";${CMAKE_SWIG_FLAGS};" MATCHES ";-noproxy;") + set(SWIG_MODULE_${name}_NAME "${name}") + set(SWIG_MODULE_${name}_EXTRA_FLAGS) + if (NOT DEFINED SWIG_MODULE_${name}_NOPROXY) + set (SWIG_MODULE_${name}_NOPROXY FALSE) + endif() + if ("-noproxy" IN_LIST CMAKE_SWIG_FLAGS) set (SWIG_MODULE_${name}_NOPROXY TRUE) endif () - if("x${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "xUNKNOWN") + + if (SWIG_MODULE_${name}_NOPROXY AND NOT "-noproxy" IN_LIST CMAKE_SWIG_FLAGS) + list (APPEND SWIG_MODULE_${name}_EXTRA_FLAGS "-noproxy") + endif() + if(SWIG_MODULE_${name}_LANGUAGE STREQUAL "UNKNOWN") message(FATAL_ERROR "SWIG Error: Language \"${language}\" not found") - elseif("x${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "xPYTHON" AND NOT SWIG_MODULE_${name}_NOPROXY) + elseif(SWIG_MODULE_${name}_LANGUAGE STREQUAL "PYTHON" AND NOT SWIG_MODULE_${name}_NOPROXY) # swig will produce a module.py containing an 'import _modulename' statement, # which implies having a corresponding _modulename.so (*NIX), _modulename.pyd (Win32), # unless the -noproxy flag is used - set(SWIG_MODULE_${name}_REAL_NAME "_${name}") - elseif("x${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "xPERL") - set(SWIG_MODULE_${name}_EXTRA_FLAGS "-shadow") + set(SWIG_MODULE_${name}_NAME "_${name}") + elseif(SWIG_MODULE_${name}_LANGUAGE STREQUAL "PERL") + list(APPEND SWIG_MODULE_${name}_EXTRA_FLAGS "-shadow") endif() endmacro() @@ -102,79 +187,108 @@ endmacro() # will be generated. This is internal swig macro. # -macro(SWIG_GET_EXTRA_OUTPUT_FILES language outfiles generatedpath infile) - set(${outfiles} "") - get_source_file_property(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename - ${infile} SWIG_MODULE_NAME) - if(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename STREQUAL "NOTFOUND") +function(SWIG_GET_EXTRA_OUTPUT_FILES language outfiles generatedpath infile) + set(files) + get_source_file_property(module_basename + "${infile}" SWIG_MODULE_NAME) + if(NOT swig_module_basename) # try to get module name from "%module foo" syntax - if ( EXISTS ${infile} ) - file ( STRINGS ${infile} _MODULE_NAME REGEX "[ ]*%module[ ]*[a-zA-Z0-9_]+.*" ) + if ( EXISTS "${infile}" ) + file ( STRINGS "${infile}" module_basename REGEX "[ ]*%module[ ]*[a-zA-Z0-9_]+.*" ) endif () - if ( _MODULE_NAME ) - string ( REGEX REPLACE "[ ]*%module[ ]*([a-zA-Z0-9_]+).*" "\\1" _MODULE_NAME "${_MODULE_NAME}" ) - set(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename "${_MODULE_NAME}") + if ( module_basename ) + string ( REGEX REPLACE "[ ]*%module[ ]*([a-zA-Z0-9_]+).*" "\\1" module_basename "${module_basename}" ) else () # try to get module name from "%module (options=...) foo" syntax - if ( EXISTS ${infile} ) - file ( STRINGS ${infile} _MODULE_NAME REGEX "[ ]*%module[ ]*\\(.*\\)[ ]*[a-zA-Z0-9_]+.*" ) + if ( EXISTS "${infile}" ) + file ( STRINGS "${infile}" module_basename REGEX "[ ]*%module[ ]*\\(.*\\)[ ]*[a-zA-Z0-9_]+.*" ) endif () - if ( _MODULE_NAME ) - string ( REGEX REPLACE "[ ]*%module[ ]*\\(.*\\)[ ]*([a-zA-Z0-9_]+).*" "\\1" _MODULE_NAME "${_MODULE_NAME}" ) - set(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename "${_MODULE_NAME}") + if ( module_basename ) + string ( REGEX REPLACE "[ ]*%module[ ]*\\(.*\\)[ ]*([a-zA-Z0-9_]+).*" "\\1" module_basename "${module_basename}" ) else () # fallback to file basename - get_filename_component(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename ${infile} NAME_WE) + get_filename_component(module_basename "${infile}" NAME_WE) endif () endif () endif() foreach(it ${SWIG_${language}_EXTRA_FILE_EXTENSIONS}) - set(extra_file "${generatedpath}/${SWIG_GET_EXTRA_OUTPUT_FILES_module_basename}${it}") - list(APPEND ${outfiles} ${extra_file}) - # Treat extra outputs as plain files regardless of language. - set_property(SOURCE "${extra_file}" PROPERTY LANGUAGE "") + set(extra_file "${generatedpath}/${module_basename}${it}") + list(APPEND files "${extra_file}") endforeach() -endmacro() + # Treat extra outputs as plain files regardless of language. + set_source_files_properties(${files} PROPERTIES LANGUAGE "") + + set (${outfiles} ${files} PARENT_SCOPE) +endfunction() # # Take swig (*.i) file and add proper custom commands for it # -macro(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile) - set(swig_full_infile ${infile}) +function(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile) get_filename_component(swig_source_file_name_we "${infile}" NAME_WE) - get_source_file_property(swig_source_file_generated ${infile} GENERATED) - get_source_file_property(swig_source_file_cplusplus ${infile} CPLUSPLUS) - get_source_file_property(swig_source_file_flags ${infile} SWIG_FLAGS) - if("${swig_source_file_flags}" STREQUAL "NOTFOUND") - set(swig_source_file_flags "") - endif() - get_filename_component(swig_source_file_fullname "${infile}" ABSOLUTE) + get_source_file_property(swig_source_file_cplusplus "${infile}" CPLUSPLUS) # If CMAKE_SWIG_OUTDIR was specified then pass it to -outdir if(CMAKE_SWIG_OUTDIR) - set(swig_outdir ${CMAKE_SWIG_OUTDIR}) + set(outdir ${CMAKE_SWIG_OUTDIR}) else() - set(swig_outdir ${CMAKE_CURRENT_BINARY_DIR}) + set(outdir ${CMAKE_CURRENT_BINARY_DIR}) endif() if(SWIG_OUTFILE_DIR) - set(swig_outfile_dir ${SWIG_OUTFILE_DIR}) + set(outfiledir ${SWIG_OUTFILE_DIR}) else() - set(swig_outfile_dir ${swig_outdir}) + set(outfiledir ${outdir}) + endif() + + if(SWIG_WORKING_DIR) + set (workingdir "${SWIG_WORKING_DIR}") + else() + set(workingdir "${outdir}") + endif() + + set (swig_source_file_flags ${CMAKE_SWIG_FLAGS}) + # handle various swig compile flags properties + get_source_file_property (include_directories "${infile}" INCLUDE_DIRECTORIES) + if (include_directories) + list (APPEND swig_source_file_flags "-I$<JOIN:${include_directories},$<SEMICOLON>-I>") + endif() + set (property "$<TARGET_PROPERTY:${name},SWIG_INCLUDE_DIRECTORIES>") + list (APPEND swig_source_file_flags "$<$<BOOL:${property}>:-I$<JOIN:${property},$<SEMICOLON>-I>>") + + set (property "$<TARGET_PROPERTY:${name},SWIG_COMPILE_DEFINITIONS>") + list (APPEND swig_source_file_flags "$<$<BOOL:${property}>:-D$<JOIN:${property},$<SEMICOLON>-D>>") + get_source_file_property (compile_definitions "${infile}" COMPILE_DEFINITIONS) + if (compile_definitions) + list (APPEND swig_source_file_flags "-D$<JOIN:${compile_definitions},$<SEMICOLON>-D>") + endif() + + list (APPEND swig_source_file_flags "$<TARGET_PROPERTY:${name},SWIG_COMPILE_OPTIONS>") + get_source_file_property (compile_options "${infile}" COMPILE_OPTIONS) + if (compile_options) + list (APPEND swig_source_file_flags ${compile_options}) + endif() + + # legacy support + get_source_file_property (swig_flags "${infile}" SWIG_FLAGS) + if (swig_flags) + list (APPEND swig_source_file_flags ${swig_flags}) endif() + get_filename_component(swig_source_file_fullname "${infile}" ABSOLUTE) + if (NOT SWIG_MODULE_${name}_NOPROXY) SWIG_GET_EXTRA_OUTPUT_FILES(${SWIG_MODULE_${name}_LANGUAGE} swig_extra_generated_files - "${swig_outdir}" + "${outdir}" "${swig_source_file_fullname}") endif() set(swig_generated_file_fullname - "${swig_outfile_dir}/${swig_source_file_name_we}") + "${outfiledir}/${swig_source_file_name_we}") # add the language into the name of the file (i.e. TCL_wrap) # this allows for the same .i file to be wrapped into different languages string(APPEND swig_generated_file_fullname @@ -188,45 +302,47 @@ macro(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile) ".c") endif() - #message("Full path to source file: ${swig_source_file_fullname}") - #message("Full path to the output file: ${swig_generated_file_fullname}") - get_directory_property(cmake_include_directories INCLUDE_DIRECTORIES) - list(REMOVE_DUPLICATES cmake_include_directories) - set(swig_include_dirs) - foreach(it ${cmake_include_directories}) - set(swig_include_dirs ${swig_include_dirs} "-I${it}") - endforeach() + get_directory_property (cmake_include_directories INCLUDE_DIRECTORIES) + list (REMOVE_DUPLICATES cmake_include_directories) + set (swig_include_dirs) + if (cmake_include_directories) + set (swig_include_dirs "-I$<JOIN:${cmake_include_directories},$<SEMICOLON>-I>") + endif() set(swig_special_flags) # default is c, so add c++ flag if it is c++ if(swig_source_file_cplusplus) - set(swig_special_flags ${swig_special_flags} "-c++") + list (APPEND swig_special_flags "-c++") endif() - if("x${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "xCSHARP") - if(NOT ";${swig_source_file_flags};${CMAKE_SWIG_FLAGS};" MATCHES ";-dllimport;") + + set (swig_extra_flags) + if(SWIG_MODULE_${name}_LANGUAGE STREQUAL "CSHARP") + if(NOT ("-dllimport" IN_LIST swig_source_file_flags OR "-dllimport" IN_LIST SWIG_MODULE_${name}_EXTRA_FLAGS)) # This makes sure that the name used in the generated DllImport # matches the library name created by CMake - set(SWIG_MODULE_${name}_EXTRA_FLAGS "-dllimport;${name}") + list (APPEND SWIG_MODULE_${name}_EXTRA_FLAGS "-dllimport" "${name}") endif() endif() - set(swig_extra_flags) - if(SWIG_MODULE_${name}_EXTRA_FLAGS) - set(swig_extra_flags ${swig_extra_flags} ${SWIG_MODULE_${name}_EXTRA_FLAGS}) + list (APPEND swig_extra_flags ${SWIG_MODULE_${name}_EXTRA_FLAGS}) + + # dependencies + set (swig_dependencies ${SWIG_MODULE_${name}_EXTRA_DEPS} $<TARGET_PROPERTY:${name},SWIG_DEPENDS>) + get_source_file_property(file_depends "${infile}" DEPENDS) + if (file_depends) + list (APPEND swig_dependencies ${file_depends}) endif() + # IMPLICIT_DEPENDS below can not handle situations where a dependent file is # removed. We need an extra step with timestamp and custom target, see #16830 # As this is needed only for Makefile generator do it conditionally if(CMAKE_GENERATOR MATCHES "Make") - get_filename_component(swig_generated_timestamp - "${swig_generated_file_fullname}" NAME_WE) - set(swig_gen_target gen_${name}_${swig_generated_timestamp}) - set(swig_generated_timestamp - "${swig_outdir}/${swig_generated_timestamp}.stamp") - set(swig_custom_output ${swig_generated_timestamp}) + __swig_compute_timestamp(${name} ${SWIG_MODULE_${name}_LANGUAGE} + "${infile}" "${workingdir}" swig_generated_timestamp) + set(swig_custom_output "${swig_generated_timestamp}") set(swig_custom_products BYPRODUCTS "${swig_generated_file_fullname}" ${swig_extra_generated_files}) set(swig_timestamp_command - COMMAND ${CMAKE_COMMAND} -E touch ${swig_generated_timestamp}) + COMMAND ${CMAKE_COMMAND} -E touch "${swig_generated_timestamp}") else() set(swig_custom_output "${swig_generated_file_fullname}" ${swig_extra_generated_files}) @@ -236,34 +352,41 @@ macro(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile) add_custom_command( OUTPUT ${swig_custom_output} ${swig_custom_products} - # Let's create the ${swig_outdir} at execution time, in case dir contains $(OutDir) - COMMAND ${CMAKE_COMMAND} -E make_directory ${swig_outdir} + # Let's create the ${outdir} at execution time, in case dir contains $(OutDir) + COMMAND "${CMAKE_COMMAND}" -E make_directory ${outdir} ${outfiledir} ${swig_timestamp_command} COMMAND "${SWIG_EXECUTABLE}" - ARGS "-${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}" - ${swig_source_file_flags} - ${CMAKE_SWIG_FLAGS} - -outdir ${swig_outdir} + "-${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}" + "${swig_source_file_flags}" + -outdir "${outdir}" ${swig_special_flags} ${swig_extra_flags} - ${swig_include_dirs} + "${swig_include_dirs}" -o "${swig_generated_file_fullname}" "${swig_source_file_fullname}" MAIN_DEPENDENCY "${swig_source_file_fullname}" - DEPENDS ${SWIG_MODULE_${name}_EXTRA_DEPS} + DEPENDS ${swig_dependencies} IMPLICIT_DEPENDS CXX "${swig_source_file_fullname}" - COMMENT "Swig source") - if(CMAKE_GENERATOR MATCHES "Make") - add_custom_target(${swig_gen_target} DEPENDS ${swig_generated_timestamp}) - endif() - unset(swig_generated_timestamp) - unset(swig_custom_output) - unset(swig_custom_products) - unset(swig_timestamp_command) + COMMENT "Swig source" + COMMAND_EXPAND_LISTS) set_source_files_properties("${swig_generated_file_fullname}" ${swig_extra_generated_files} PROPERTIES GENERATED 1) - set(${outfiles} "${swig_generated_file_fullname}" ${swig_extra_generated_files}) -endmacro() + + ## add all properties for generated file to various properties + get_property (include_directories SOURCE "${infile}" PROPERTY GENERATED_INCLUDE_DIRECTORIES) + set_property (SOURCE "${swig_generated_file_fullname}" PROPERTY INCLUDE_DIRECTORIES ${include_directories} $<TARGET_PROPERTY:${name},SWIG_GENERATED_INCLUDE_DIRECTORIES>) + + get_property (compile_definitions SOURCE "${infile}" PROPERTY GENERATED_COMPILE_DEFINITIONS) + set_property (SOURCE "${swig_generated_file_fullname}" PROPERTY COMPILE_DEFINITIONS $<TARGET_PROPERTY:${name},SWIG_GENERATED_COMPILE_DEFINITIONS> ${compile_definitions}) + + get_property (compile_options SOURCE "${infile}" PROPERTY GENERATED_COMPILE_OPTIONS) + set_property (SOURCE "${swig_generated_file_fullname}" PROPERTY COMPILE_OPTIONS $<TARGET_PROPERTY:${name},SWIG_GENERATED_COMPILE_OPTIONS> ${compile_options}) + + set(${outfiles} "${swig_generated_file_fullname}" ${swig_extra_generated_files} PARENT_SCOPE) + + # legacy support + set (swig_generated_file_fullname "${swig_generated_file_fullname}" PARENT_SCOPE) +endfunction() # # Create Swig module @@ -277,13 +400,26 @@ macro(SWIG_ADD_MODULE name language) endmacro() -macro(SWIG_ADD_LIBRARY name) - set(options "") +function(SWIG_ADD_LIBRARY name) + set(options NO_PROXY) set(oneValueArgs LANGUAGE - TYPE) + TYPE + OUTPUT_DIR + OUTFILE_DIR) set(multiValueArgs SOURCES) cmake_parse_arguments(_SAM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + if (TARGET ${name}) + # a target with same name is already defined. + # call NOW add_library command to raise the most useful error message + add_library(${name}) + return() + endif() + + if (_SAM_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "SWIG_ADD_LIBRARY: ${_SAM_UNPARSED_ARGUMENTS}: unexpected arguments") + endif() + if(NOT DEFINED _SAM_LANGUAGE) message(FATAL_ERROR "SWIG_ADD_LIBRARY: Missing LANGUAGE argument") endif() @@ -294,50 +430,83 @@ macro(SWIG_ADD_LIBRARY name) if(NOT DEFINED _SAM_TYPE) set(_SAM_TYPE MODULE) - elseif("${_SAM_TYPE}" STREQUAL "USE_BUILD_SHARED_LIBS") + elseif(_SAM_TYPE STREQUAL "USE_BUILD_SHARED_LIBS") unset(_SAM_TYPE) endif() - swig_module_initialize(${name} ${_SAM_LANGUAGE}) + set (workingdir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${name}.dir") + # set special variable to pass extra information to command SWIG_ADD_SOURCE_TO_MODULE + # which cannot be changed due to legacy compatibility + set (SWIG_WORKING_DIR "${workingdir}") - set(swig_dot_i_sources) - set(swig_other_sources) - foreach(it ${_SAM_SOURCES}) - if(${it} MATCHES "\\.i$") - set(swig_dot_i_sources ${swig_dot_i_sources} "${it}") + set (outputdir "${_SAM_OUTPUT_DIR}") + if (NOT _SAM_OUTPUT_DIR) + if (CMAKE_SWIG_OUTDIR) + set (outputdir "${CMAKE_SWIG_OUTDIR}") else() - set(swig_other_sources ${swig_other_sources} "${it}") + set (outputdir "${CMAKE_CURRENT_BINARY_DIR}") endif() - endforeach() + endif() + + set (outfiledir "${_SAM_OUTFILE_DIR}") + if(NOT _SAM_OUTFILE_DIR) + if (SWIG_OUTFILE_DIR) + set (outfiledir "${SWIG_OUTFILE_DIR}") + else() + if (_SAM_OUTPUT_DIR OR CMAKE_SWIG_OUTDIR) + set (outfiledir "${outputdir}") + else() + set (outfiledir "${workingdir}") + endif() + endif() + endif() + # set again, locally, predefined variables to ensure compatibility + # with command SWIG_ADD_SOURCE_TO_MODULE + set(CMAKE_SWIG_OUTDIR "${outputdir}") + set(SWIG_OUTFILE_DIR "${outfiledir}") + + set (SWIG_MODULE_${name}_NOPROXY ${_SAM_NO_PROXY}) + swig_module_initialize(${name} ${_SAM_LANGUAGE}) + + set(swig_dot_i_sources ${_SAM_SOURCES}) + list(FILTER swig_dot_i_sources INCLUDE REGEX "\\.i$") + set(swig_other_sources ${_SAM_SOURCES}) + list(REMOVE_ITEM swig_other_sources ${swig_dot_i_sources}) set(swig_generated_sources) - set(swig_generated_targets) - foreach(it ${swig_dot_i_sources}) - SWIG_ADD_SOURCE_TO_MODULE(${name} swig_generated_source ${it}) - set(swig_generated_sources ${swig_generated_sources} "${swig_generated_source}") - list(APPEND swig_generated_targets "${swig_gen_target}") + set(swig_generated_timestamps) + foreach(swig_it IN LISTS swig_dot_i_sources) + SWIG_ADD_SOURCE_TO_MODULE(${name} swig_generated_source "${swig_it}") + list (APPEND swig_generated_sources "${swig_generated_source}") + if(CMAKE_GENERATOR MATCHES "Make") + __swig_compute_timestamp(${name} ${SWIG_MODULE_${name}_LANGUAGE} "${swig_it}" + "${workingdir}" swig_timestamp) + list (APPEND swig_generated_timestamps "${swig_timestamp}") + endif() endforeach() - get_directory_property(swig_extra_clean_files ADDITIONAL_MAKE_CLEAN_FILES) - set_directory_properties(PROPERTIES - ADDITIONAL_MAKE_CLEAN_FILES "${swig_extra_clean_files};${swig_generated_sources}") - add_library(${SWIG_MODULE_${name}_REAL_NAME} + set_property (DIRECTORY APPEND PROPERTY + ADDITIONAL_MAKE_CLEAN_FILES ${swig_generated_sources} ${swig_generated_timestamps}) + + add_library(${name} ${_SAM_TYPE} ${swig_generated_sources} ${swig_other_sources}) + set_target_properties(${name} PROPERTIES OUTPUT_NAME "${SWIG_MODULE_${name}_NAME}") if(CMAKE_GENERATOR MATCHES "Make") # see IMPLICIT_DEPENDS above - add_dependencies(${SWIG_MODULE_${name}_REAL_NAME} ${swig_generated_targets}) + add_custom_target(${name}_swig_compilation DEPENDS ${swig_generated_timestamps}) + add_dependencies(${name} ${name}_swig_compilation) endif() - if("${_SAM_TYPE}" STREQUAL "MODULE") - set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES NO_SONAME ON) + if(_SAM_TYPE STREQUAL "MODULE") + set_target_properties(${name} PROPERTIES NO_SONAME ON) endif() string(TOLOWER "${_SAM_LANGUAGE}" swig_lowercase_language) - if ("${swig_lowercase_language}" STREQUAL "octave") - set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "") - set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".oct") - elseif ("${swig_lowercase_language}" STREQUAL "go") - set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "") - elseif ("${swig_lowercase_language}" STREQUAL "java") + if (swig_lowercase_language STREQUAL "octave") + set_target_properties(${name} PROPERTIES PREFIX "") + set_target_properties(${name} PROPERTIES SUFFIX ".oct") + elseif (swig_lowercase_language STREQUAL "go") + set_target_properties(${name} PROPERTIES PREFIX "") + elseif (swig_lowercase_language STREQUAL "java") if (APPLE) # In java you want: # System.loadLibrary("LIBRARY"); @@ -345,15 +514,15 @@ macro(SWIG_ADD_LIBRARY name) # MacOS : libLIBRARY.jnilib # Windows: LIBRARY.dll # Linux : libLIBRARY.so - set_target_properties (${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".jnilib") + set_target_properties (${name} PROPERTIES SUFFIX ".jnilib") endif () - elseif ("${swig_lowercase_language}" STREQUAL "lua") - if("${_SAM_TYPE}" STREQUAL "MODULE") - set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "") + elseif (swig_lowercase_language STREQUAL "lua") + if(_SAM_TYPE STREQUAL "MODULE") + set_target_properties(${name} PROPERTIES PREFIX "") endif() - elseif ("${swig_lowercase_language}" STREQUAL "python") + elseif (swig_lowercase_language STREQUAL "python") # this is only needed for the python case where a _modulename.so is generated - set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "") + set_target_properties(${name} PROPERTIES PREFIX "") # Python extension modules on Windows must have the extension ".pyd" # instead of ".dll" as of Python 2.5. Older python versions do support # this suffix. @@ -363,34 +532,60 @@ macro(SWIG_ADD_LIBRARY name) # .pyd is now the only filename extension that will be searched for. # </quote> if(WIN32 AND NOT CYGWIN) - set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".pyd") + set_target_properties(${name} PROPERTIES SUFFIX ".pyd") endif() - elseif ("${swig_lowercase_language}" STREQUAL "r") - set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "") - elseif ("${swig_lowercase_language}" STREQUAL "ruby") + elseif (swig_lowercase_language STREQUAL "r") + set_target_properties(${name} PROPERTIES PREFIX "") + elseif (swig_lowercase_language STREQUAL "ruby") # In ruby you want: # require 'LIBRARY' # then ruby will look for a library whose name is platform dependent, namely # MacOS : LIBRARY.bundle # Windows: LIBRARY.dll # Linux : LIBRARY.so - set_target_properties (${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "") + set_target_properties (${name} PROPERTIES PREFIX "") + if (APPLE) + set_target_properties (${name} PROPERTIES SUFFIX ".bundle") + endif () + elseif (swig_lowercase_language STREQUAL "perl") + # assume empty prefix because we expect the module to be dynamically loaded + set_target_properties (${name} PROPERTIES PREFIX "") if (APPLE) - set_target_properties (${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".bundle") + set_target_properties (${name} PROPERTIES SUFFIX ".dylib") endif () else() # assume empty prefix because we expect the module to be dynamically loaded - set_target_properties (${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "") + set_target_properties (${name} PROPERTIES PREFIX "") endif () -endmacro() + # target property SWIG_SUPPORT_FILES lists proxy support files + if (NOT SWIG_MODULE_${name}_NOPROXY) + string(TOUPPER "${_SAM_LANGUAGE}" swig_uppercase_language) + foreach (swig_it IN LISTS SWIG_${swig_uppercase_language}_EXTRA_FILE_EXTENSIONS) + set (swig_support_files ${swig_generated_sources}) + list (FILTER swig_support_files INCLUDE REGEX ".*${swig_it}$") + set_property (TARGET ${name} APPEND PROPERTY SWIG_SUPPORT_FILES ${swig_support_files}) + endforeach() + endif() + + # to ensure legacy behavior, export some variables + set (SWIG_MODULE_${name}_LANGUAGE "${SWIG_MODULE_${name}_LANGUAGE}" PARENT_SCOPE) + set (SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG "${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}" PARENT_SCOPE) + set (SWIG_MODULE_${name}_REAL_NAME "${name}" PARENT_SCOPE) + set (SWIG_MODULE_${name}_NOPROXY "${SWIG_MODULE_${name}_NOPROXY}" PARENT_SCOPE) + set (SWIG_MODULE_${name}_EXTRA_FLAGS "${SWIG_MODULE_${name}_EXTRA_FLAGS}" PARENT_SCOPE) + # the last one is a bit crazy but it is documented, so... + # NOTA: works as expected if only ONE input file is specified + set (swig_generated_file_fullname "${swig_generated_file_fullname}" PARENT_SCOPE) +endfunction() # # Like TARGET_LINK_LIBRARIES but for swig modules # -macro(SWIG_LINK_LIBRARIES name) +function(SWIG_LINK_LIBRARIES name) + message(DEPRECATION "SWIG_LINK_LIBRARIES is deprecated. Use TARGET_LINK_LIBRARIES instead.") if(SWIG_MODULE_${name}_REAL_NAME) - target_link_libraries(${SWIG_MODULE_${name}_REAL_NAME} ${ARGN}) + target_link_libraries(${name} ${ARGN}) else() message(SEND_ERROR "Cannot find Swig library \"${name}\".") endif() -endmacro() +endfunction() diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index a0010a2..e547356 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -131,6 +131,8 @@ set(SRCS LexerParser/cmListFileLexer.c LexerParser/cmListFileLexer.in.l + cmAffinity.cxx + cmAffinity.h cmArchiveWrite.cxx cmBase32.cxx cmCacheManager.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 50a14da..ca63858 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 11) -set(CMake_VERSION_PATCH 0) -set(CMake_VERSION_RC 3) +set(CMake_VERSION_PATCH 20180319) +#set(CMake_VERSION_RC 1) diff --git a/Source/CMakeVersionCompute.cmake b/Source/CMakeVersionCompute.cmake index 79264ed..72a5800 100644 --- a/Source/CMakeVersionCompute.cmake +++ b/Source/CMakeVersionCompute.cmake @@ -32,7 +32,12 @@ endif() # components in the RC file are 16-bit integers so we may have to # split the patch component. if(CMake_VERSION_PATCH MATCHES "^([0-9]+)([0-9][0-9][0-9][0-9])$") - set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMAKE_MATCH_1},${CMAKE_MATCH_2}) + set(CMake_RCVERSION_YEAR "${CMAKE_MATCH_1}") + set(CMake_RCVERSION_MONTH_DAY "${CMAKE_MATCH_2}") + string(REGEX REPLACE "^0+" "" CMake_RCVERSION_MONTH_DAY "${CMake_RCVERSION_MONTH_DAY}") + set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMake_RCVERSION_YEAR},${CMake_RCVERSION_MONTH_DAY}) + unset(CMake_RCVERSION_MONTH_DAY) + unset(CMake_RCVERSION_YEAR) else() set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMake_VERSION_PATCH}) endif() diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx index 9ff547a..00fbdab 100644 --- a/Source/CPack/cmCPackArchiveGenerator.cxx +++ b/Source/CPack/cmCPackArchiveGenerator.cxx @@ -9,6 +9,7 @@ #include "cmSystemTools.h" #include "cmWorkingDirectory.h" +#include <cstring> #include <ostream> #include <utility> #include <vector> @@ -51,6 +52,7 @@ int cmCPackArchiveGenerator::InitializeInternal() this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1"); return this->Superclass::InitializeInternal(); } + int cmCPackArchiveGenerator::addOneComponentToArchive( cmArchiveWrite& archive, cmCPackComponent* component) { @@ -61,6 +63,13 @@ int cmCPackArchiveGenerator::addOneComponentToArchive( localToplevel += "/" + component->Name; // Change to local toplevel cmWorkingDirectory workdir(localToplevel); + if (workdir.Failed()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Failed to change working directory to " + << localToplevel << " : " + << std::strerror(workdir.GetLastResult()) << std::endl); + return 0; + } std::string filePrefix; if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) { filePrefix = this->GetOption("CPACK_PACKAGE_FILE_NAME"); @@ -237,6 +246,13 @@ int cmCPackArchiveGenerator::PackageFiles() // CASE 3 : NON COMPONENT package. DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive); cmWorkingDirectory workdir(toplevel); + if (workdir.Failed()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Failed to change working directory to " + << toplevel << " : " + << std::strerror(workdir.GetLastResult()) << std::endl); + return 0; + } for (std::string const& file : files) { // Get the relative path to the file std::string rp = cmSystemTools::RelativePath(toplevel, file); diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index d838b30..d41a9e5 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -6,6 +6,7 @@ #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" #include <algorithm> +#include <cstring> #include <memory> // IWYU pragma: keep #include <utility> @@ -404,6 +405,13 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( cmCPackLogger(cmCPackLog::LOG_DEBUG, "Change dir to: " << goToDir << std::endl); cmWorkingDirectory workdir(goToDir); + if (workdir.Failed()) { + cmCPackLogger( + cmCPackLog::LOG_ERROR, "Failed to change working directory to " + << goToDir << " : " << std::strerror(workdir.GetLastResult()) + << std::endl); + return 0; + } for (auto const& symlinked : symlinkedFiles) { cmCPackLogger(cmCPackLog::LOG_DEBUG, "Will create a symlink: " << symlinked.second << "--> " << symlinked.first diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index 2e1ea4c..b2c68e7 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -11,6 +11,7 @@ #include "cmsys/Process.h" #include <chrono> +#include <cstring> #include <ratio> #include <stdlib.h> @@ -196,6 +197,16 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) cmSystemTools::MakeDirectory(this->BinaryDir); } cmWorkingDirectory workdir(this->BinaryDir); + if (workdir.Failed()) { + auto msg = "Failed to change working directory to " + this->BinaryDir + + " : " + std::strerror(workdir.GetLastResult()) + "\n"; + if (outstring) { + *outstring = msg; + } else { + cmCTestLog(this->CTest, ERROR_MESSAGE, msg); + } + return 1; + } if (this->BuildNoCMake) { // Make the generator available for the Build call below. @@ -307,7 +318,16 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) // run the test from the this->BuildRunDir if set if (!this->BuildRunDir.empty()) { out << "Run test in directory: " << this->BuildRunDir << "\n"; - cmSystemTools::ChangeDirectory(this->BuildRunDir); + if (!workdir.SetDirectory(this->BuildRunDir)) { + out << "Failed to change working directory : " + << std::strerror(workdir.GetLastResult()) << "\n"; + if (outstring) { + *outstring = out.str(); + } else { + cmCTestLog(this->CTest, ERROR_MESSAGE, out.str()); + } + return 1; + } } out << "Running test command: \"" << fullPath << "\""; for (std::string const& testCommandArg : this->TestCommandArgs) { diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 9c66e73..6cf0ac2 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -23,6 +23,7 @@ #include "cmsys/RegularExpression.hxx" #include <algorithm> #include <chrono> +#include <cstring> #include <iomanip> #include <iterator> #include <sstream> @@ -975,7 +976,12 @@ int cmCTestCoverageHandler::HandleGCovCoverage( std::string testingDir = this->CTest->GetBinaryDir() + "/Testing"; std::string tempDir = testingDir + "/CoverageInfo"; - cmSystemTools::MakeDirectory(tempDir); + if (!cmSystemTools::MakeDirectory(tempDir)) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Unable to make directory: " << tempDir << std::endl); + cont->Error++; + return 0; + } cmWorkingDirectory workdir(tempDir); int gcovStyle = 0; @@ -1376,6 +1382,14 @@ int cmCTestCoverageHandler::HandleLCovCoverage( this->Quiet); std::string fileDir = cmSystemTools::GetFilenamePath(f); cmWorkingDirectory workdir(fileDir); + if (workdir.Failed()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Unable to change working directory to " + << fileDir << " : " + << std::strerror(workdir.GetLastResult()) << std::endl); + cont->Error++; + continue; + } cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Current coverage dir: " << fileDir << std::endl, @@ -1600,6 +1614,12 @@ bool cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files) gl.RecurseThroughSymlinksOff(); std::string buildDir = this->CTest->GetCTestConfiguration("BuildDirectory"); cmWorkingDirectory workdir(buildDir); + if (workdir.Failed()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Unable to change working directory to " << buildDir + << std::endl); + return false; + } // Run profmerge to merge all *.dyn files into dpi files if (!cmSystemTools::RunSingleCommand("profmerge")) { diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index 5a7baf5..1fff2fa 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -9,6 +9,7 @@ #include "cmWorkingDirectory.h" #include "cmake.h" +#include <cstring> #include <sstream> #include <stdlib.h> @@ -218,6 +219,21 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, } cmWorkingDirectory workdir( this->CTest->GetCTestConfiguration("BuildDirectory")); + if (workdir.Failed()) { + this->SetError("failed to change directory to " + + this->CTest->GetCTestConfiguration("BuildDirectory") + + " : " + std::strerror(workdir.GetLastResult())); + if (capureCMakeError) { + this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR], + "-1"); + cmCTestLog(this->CTest, ERROR_MESSAGE, this->GetName() + << " " << this->GetError() << "\n"); + // return success because failure is recorded in CAPTURE_CMAKE_ERROR + return true; + } + return false; + } + int res = handler->ProcessHandler(); if (this->Values[ct_RETURN_VALUE] && *this->Values[ct_RETURN_VALUE]) { std::ostringstream str; diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 50c2d86..14b5caa 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestMultiProcessHandler.h" +#include "cmAffinity.h" #include "cmCTest.h" #include "cmCTestRunTest.h" #include "cmCTestScriptHandler.h" @@ -19,6 +20,7 @@ #include <algorithm> #include <chrono> +#include <cstring> #include <iomanip> #include <list> #include <math.h> @@ -53,6 +55,8 @@ cmCTestMultiProcessHandler::cmCTestMultiProcessHandler() this->TestLoad = 0; this->Completed = 0; this->RunningCount = 0; + this->ProcessorsAvailable = cmAffinity::GetProcessorsAvailable(); + this->HaveAffinity = this->ProcessorsAvailable.size(); this->StopTimePassed = false; this->HasCycles = false; this->SerialTestRunning = false; @@ -127,6 +131,21 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test) return false; } + if (this->HaveAffinity && this->Properties[test]->WantAffinity) { + size_t needProcessors = this->GetProcessorsUsed(test); + if (needProcessors > this->ProcessorsAvailable.size()) { + return false; + } + std::vector<size_t> affinity; + affinity.reserve(needProcessors); + for (size_t i = 0; i < needProcessors; ++i) { + auto p = this->ProcessorsAvailable.begin(); + affinity.push_back(*p); + this->ProcessorsAvailable.erase(p); + } + this->Properties[test]->Affinity = std::move(affinity); + } + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "test " << test << "\n", this->Quiet); this->TestRunningMap[test] = true; // mark the test as running @@ -151,13 +170,19 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test) } } - cmWorkingDirectory workdir(this->Properties[test]->Directory); - - // Lock the resources we'll be using + // Always lock the resources we'll be using, even if we fail to set the + // working directory because FinishTestProcess() will try to unlock them this->LockResources(test); - if (testRun->StartTest(this->Total)) { - return true; + cmWorkingDirectory workdir(this->Properties[test]->Directory); + if (workdir.Failed()) { + testRun->StartFailure("Failed to change working directory to " + + this->Properties[test]->Directory + " : " + + std::strerror(workdir.GetLastResult())); + } else { + if (testRun->StartTest(this->Total)) { + return true; + } } this->FinishTestProcess(testRun, false); @@ -200,6 +225,11 @@ inline size_t cmCTestMultiProcessHandler::GetProcessorsUsed(int test) if (processors > this->ParallelLevel) { processors = this->ParallelLevel; } + // Cap tests that want affinity to the maximum affinity available. + if (this->HaveAffinity && processors > this->HaveAffinity && + this->Properties[test]->WantAffinity) { + processors = this->HaveAffinity; + } return processors; } @@ -398,6 +428,11 @@ void cmCTestMultiProcessHandler::FinishTestProcess(cmCTestRunTest* runner, this->UnlockResources(test); this->RunningCount -= GetProcessorsUsed(test); + for (auto p : properties->Affinity) { + this->ProcessorsAvailable.insert(p); + } + properties->Affinity.clear(); + delete runner; if (started) { this->StartNextTests(); @@ -666,6 +701,8 @@ void cmCTestMultiProcessHandler::PrintTestList() count++; cmCTestTestHandler::cmCTestTestProperties& p = *it.second; + // Don't worry if this fails, we are only showing the test list, not + // running the tests cmWorkingDirectory workdir(p.Directory); cmCTestRunTest testRun(*this); diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index 7837ff9..19e1a35 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -119,6 +119,8 @@ protected: // Number of tests that are complete size_t Completed; size_t RunningCount; + std::set<size_t> ProcessorsAvailable; + size_t HaveAffinity; bool StopTimePassed; // list of test properties (indices concurrent to the test map) PropertiesMap Properties; diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 30ad38c..8d8ebaa 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -14,6 +14,7 @@ #include "cmsys/RegularExpression.hxx" #include <chrono> #include <cmAlgorithms.h> +#include <cstring> #include <iomanip> #include <ratio> #include <sstream> @@ -248,11 +249,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) *this->TestHandler->LogFile << "Test time = " << buf << std::endl; } - // Set the working directory to the tests directory to process Dart files. - { - cmWorkingDirectory workdir(this->TestProperties->Directory); - this->DartProcessing(); - } + this->DartProcessing(); // if this is doing MemCheck then all the output needs to be put into // Output since that is what is parsed by cmCTestMemCheckHandler @@ -338,6 +335,13 @@ bool cmCTestRunTest::StartAgain() this->RunAgain = false; // reset // change to tests directory cmWorkingDirectory workdir(this->TestProperties->Directory); + if (workdir.Failed()) { + this->StartFailure("Failed to change working directory to " + + this->TestProperties->Directory + " : " + + std::strerror(workdir.GetLastResult())); + return true; + } + this->StartTest(this->TotalNumberOfTests); return true; } @@ -386,6 +390,37 @@ void cmCTestRunTest::MemCheckPostProcess() handler->PostProcessTest(this->TestResult, this->Index); } +void cmCTestRunTest::StartFailure(std::string const& output) +{ + // Still need to log the Start message so the test summary records our + // attempt to start this test + cmCTestLog(this->CTest, HANDLER_OUTPUT, + std::setw(2 * getNumWidth(this->TotalNumberOfTests) + 8) + << "Start " + << std::setw(getNumWidth(this->TestHandler->GetMaxIndex())) + << this->TestProperties->Index << ": " + << this->TestProperties->Name << std::endl); + + this->ProcessOutput.clear(); + if (!output.empty()) { + *this->TestHandler->LogFile << output << std::endl; + cmCTestLog(this->CTest, ERROR_MESSAGE, output << std::endl); + } + + this->TestResult.Properties = this->TestProperties; + this->TestResult.ExecutionTime = cmDuration::zero(); + this->TestResult.CompressOutput = false; + this->TestResult.ReturnValue = -1; + this->TestResult.CompletionStatus = "Failed to start"; + this->TestResult.Status = cmCTestTestHandler::NOT_RUN; + this->TestResult.TestCount = this->TestProperties->Index; + this->TestResult.Name = this->TestProperties->Name; + this->TestResult.Path = this->TestProperties->Directory; + this->TestResult.Output = output; + this->TestResult.FullCommandLine.clear(); + this->TestProcess = cm::make_unique<cmProcess>(*this); +} + // Starts the execution of a test. Returns once it has started bool cmCTestRunTest::StartTest(size_t total) { @@ -515,7 +550,8 @@ bool cmCTestRunTest::StartTest(size_t total) } return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout, - &this->TestProperties->Environment); + &this->TestProperties->Environment, + &this->TestProperties->Affinity); } void cmCTestRunTest::ComputeArguments() @@ -591,7 +627,8 @@ void cmCTestRunTest::DartProcessing() } bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout, - std::vector<std::string>* environment) + std::vector<std::string>* environment, + std::vector<size_t>* affinity) { this->TestProcess = cm::make_unique<cmProcess>(*this); this->TestProcess->SetId(this->Index); @@ -637,7 +674,8 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout, cmSystemTools::AppendEnv(*environment); } - return this->TestProcess->StartProcess(this->MultiTestHandler.Loop); + return this->TestProcess->StartProcess(this->MultiTestHandler.Loop, + affinity); } void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total) diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index 4d57357..3b1d674 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -74,6 +74,8 @@ public: bool StartAgain(); + void StartFailure(std::string const& output); + cmCTest* GetCTest() const { return this->CTest; } void FinalizeTest(); @@ -83,7 +85,8 @@ private: void DartProcessing(); void ExeNotFound(std::string exe); bool ForkProcess(cmDuration testTimeOut, bool explicitTimeout, - std::vector<std::string>* environment); + std::vector<std::string>* environment, + std::vector<size_t>* affinity); void WriteLogOutputTop(size_t completed, size_t total); // Run post processing of the process output for MemCheck void MemCheckPostProcess(); diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index e0bffd4..5fff730 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -527,7 +527,7 @@ int cmCTestScriptHandler::RunConfigurationScript( return result; } - // only run the curent script if we should + // only run the current script if we should if (this->Makefile && this->Makefile->IsOn("CTEST_RUN_CURRENT_SCRIPT") && this->ShouldRunCurrentScript) { return this->RunCurrentScript(); diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 08d05c8..3bab81e 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -7,6 +7,7 @@ #include "cm_jsoncpp_value.h" #include "cmsys/Process.h" #include <chrono> +#include <cstring> #include <sstream> #include <stdio.h> #include <stdlib.h> @@ -1532,6 +1533,15 @@ int cmCTestSubmitHandler::ProcessHandler() // change to the build directory so that we can uses a relative path // on windows since scp doesn't support "c:" a drive in the path cmWorkingDirectory workdir(buildDirectory); + if (workdir.Failed()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + " Failed to change directory to " + << buildDirectory << " : " + << std::strerror(workdir.GetLastResult()) << std::endl); + ofs << " Failed to change directory to " << buildDirectory << " : " + << std::strerror(workdir.GetLastResult()) << std::endl; + return -1; + } if (!this->SubmitUsingSCP(this->CTest->GetCTestConfiguration("ScpCommand"), "Testing/" + this->CTest->GetCurrentTag(), files, @@ -1551,6 +1561,15 @@ int cmCTestSubmitHandler::ProcessHandler() // change to the build directory so that we can uses a relative path // on windows since scp doesn't support "c:" a drive in the path cmWorkingDirectory workdir(buildDirectory); + if (workdir.Failed()) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + " Failed to change directory to " + << buildDirectory << " : " + << std::strerror(workdir.GetLastResult()) << std::endl); + ofs << " Failed to change directory to " << buildDirectory << " : " + << std::strerror(workdir.GetLastResult()) << std::endl; + return -1; + } cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Change directory: " << buildDirectory << std::endl, this->Quiet); diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 84d8926..cbaf984 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -6,6 +6,7 @@ #include <cmsys/Base64.h> #include <cmsys/Directory.hxx> #include <cmsys/RegularExpression.hxx> +#include <cstring> #include <functional> #include <iomanip> #include <iterator> @@ -14,7 +15,6 @@ #include <sstream> #include <stdio.h> #include <stdlib.h> -#include <string.h> #include <time.h> #include "cmAlgorithms.h" @@ -85,6 +85,11 @@ bool cmCTestSubdirCommand::InitialPass(std::vector<std::string> const& args, bool readit = false; { cmWorkingDirectory workdir(fname); + if (workdir.Failed()) { + this->SetError("Failed to change directory to " + fname + " : " + + std::strerror(workdir.GetLastResult())); + return false; + } const char* testFilename; if (cmSystemTools::FileExists("CTestTestfile.cmake")) { // does the CTestTestfile.cmake exist ? @@ -2165,6 +2170,9 @@ bool cmCTestTestHandler::SetTestsProperties( rt.Processors = 1; } } + if (key == "PROCESSOR_AFFINITY") { + rt.WantAffinity = cmSystemTools::IsOn(val.c_str()); + } if (key == "SKIP_RETURN_CODE") { rt.SkipReturnCode = atoi(val.c_str()); if (rt.SkipReturnCode < 0 || rt.SkipReturnCode > 255) { @@ -2336,6 +2344,7 @@ bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args) test.ExplicitTimeout = false; test.Cost = 0; test.Processors = 1; + test.WantAffinity = false; test.SkipReturnCode = -1; test.PreviousRuns = 0; if (this->UseIncludeRegExpFlag && diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index f4978b6..d2694a1 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -130,6 +130,8 @@ public: int Index; // Requested number of process slots int Processors; + bool WantAffinity; + std::vector<size_t> Affinity; // return code of test which will mark test as "not run" int SkipReturnCode; std::vector<std::string> Environment; diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 09ed0a9..5c9b169 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -83,7 +83,7 @@ void cmProcess::SetCommandArguments(std::vector<std::string> const& args) this->Arguments = args; } -bool cmProcess::StartProcess(uv_loop_t& loop) +bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity) { this->ProcessState = cmProcess::State::Error; if (this->Command.empty()) { @@ -138,6 +138,22 @@ bool cmProcess::StartProcess(uv_loop_t& loop) options.stdio_count = 3; // in, out and err options.exit_cb = &cmProcess::OnExitCB; options.stdio = stdio; +#if !defined(CMAKE_USE_SYSTEM_LIBUV) + std::vector<char> cpumask; + if (affinity && !affinity->empty()) { + cpumask.resize(static_cast<size_t>(uv_cpumask_size()), 0); + for (auto p : *affinity) { + cpumask[p] = 1; + } + options.cpumask = cpumask.data(); + options.cpumask_size = cpumask.size(); + } else { + options.cpumask = nullptr; + options.cpumask_size = 0; + } +#else + static_cast<void>(affinity); +#endif status = uv_read_start(pipe_reader, &cmProcess::OnAllocateCB, &cmProcess::OnReadCB); diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h index 20e24b9..b2d87fa 100644 --- a/Source/CTest/cmProcess.h +++ b/Source/CTest/cmProcess.h @@ -36,7 +36,7 @@ public: void ChangeTimeout(cmDuration t); void ResetStartTime(); // Return true if the process starts - bool StartProcess(uv_loop_t& loop); + bool StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity); enum class State { diff --git a/Source/cmAffinity.cxx b/Source/cmAffinity.cxx new file mode 100644 index 0000000..bdf1f42 --- /dev/null +++ b/Source/cmAffinity.cxx @@ -0,0 +1,62 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmAffinity.h" + +#include "cm_uv.h" + +#ifndef CMAKE_USE_SYSTEM_LIBUV +#ifdef _WIN32 +#define CM_HAVE_CPU_AFFINITY +#include <windows.h> +#elif defined(__linux__) || defined(__FreeBSD__) +#define CM_HAVE_CPU_AFFINITY +#include <pthread.h> +#include <sched.h> +#if defined(__FreeBSD__) +#include <pthread_np.h> +#include <sys/cpuset.h> +#include <sys/param.h> +#endif +#if defined(__linux__) +typedef cpu_set_t cm_cpuset_t; +#else +typedef cpuset_t cm_cpuset_t; +#endif +#endif +#endif + +namespace cmAffinity { + +std::set<size_t> GetProcessorsAvailable() +{ + std::set<size_t> processorsAvailable; +#ifdef CM_HAVE_CPU_AFFINITY + int cpumask_size = uv_cpumask_size(); + if (cpumask_size > 0) { +#ifdef _WIN32 + DWORD_PTR procmask; + DWORD_PTR sysmask; + if (GetProcessAffinityMask(GetCurrentProcess(), &procmask, &sysmask) != + 0) { + for (int i = 0; i < cpumask_size; ++i) { + if (procmask & (((DWORD_PTR)1) << i)) { + processorsAvailable.insert(i); + } + } + } +#else + cm_cpuset_t cpuset; + CPU_ZERO(&cpuset); // NOLINT(clang-tidy) + if (pthread_getaffinity_np(pthread_self(), sizeof(cpuset), &cpuset) == 0) { + for (int i = 0; i < cpumask_size; ++i) { + if (CPU_ISSET(i, &cpuset)) { + processorsAvailable.insert(i); + } + } + } +#endif + } +#endif + return processorsAvailable; +} +} diff --git a/Source/cmAffinity.h b/Source/cmAffinity.h new file mode 100644 index 0000000..3775bae --- /dev/null +++ b/Source/cmAffinity.h @@ -0,0 +1,12 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once +#include "cmConfigure.h" // IWYU pragma: keep + +#include <cstddef> +#include <set> + +namespace cmAffinity { + +std::set<size_t> GetProcessorsAvailable(); +} diff --git a/Source/cmCTest.h b/Source/cmCTest.h index 673a40e..b2f4f25 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -347,7 +347,7 @@ public: const std::string& cmake_var, bool suppress = false); - /** Make string safe to be send as an URL */ + /** Make string safe to be sent as a URL */ static std::string MakeURLSafe(const std::string&); /** Decode a URL to the original string. */ diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index fab2445..85ac985 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -160,14 +160,14 @@ bool cmCacheManager::LoadCache(const std::string& path, bool internal, currentcwd += "/CMakeCache.txt"; oldcwd += "/CMakeCache.txt"; if (!cmSystemTools::SameFile(oldcwd, currentcwd)) { - std::string message = - std::string("The current CMakeCache.txt directory ") + currentcwd + - std::string(" is different than the directory ") + - std::string(this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR")) + - std::string(" where CMakeCache.txt was created. This may result " - "in binaries being created in the wrong place. If you " - "are not sure, reedit the CMakeCache.txt"); - cmSystemTools::Error(message.c_str()); + std::ostringstream message; + message << "The current CMakeCache.txt directory " << currentcwd + << " is different than the directory " + << this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR") + << " where CMakeCache.txt was created. This may result " + "in binaries being created in the wrong place. If you " + "are not sure, reedit the CMakeCache.txt"; + cmSystemTools::Error(message.str().c_str()); } } return true; diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 8a5a6de..e00450f 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -611,6 +611,9 @@ void cmComputeLinkInformation::AddItem(std::string const& item, if (!libName.empty()) { this->AddItem(libName, nullptr); } + } else if (tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) { + // Ignore object library! + // Its object-files should already have been extracted for linking. } else { // Decide whether to use an import library. bool implib = diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index 18767a3..efdd3a5 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -211,11 +211,11 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) if (depender->GetType() != cmStateEnums::EXECUTABLE && depender->GetType() != cmStateEnums::STATIC_LIBRARY && depender->GetType() != cmStateEnums::SHARED_LIBRARY && - depender->GetType() != cmStateEnums::MODULE_LIBRARY) { + depender->GetType() != cmStateEnums::MODULE_LIBRARY && + depender->GetType() != cmStateEnums::OBJECT_LIBRARY) { this->GlobalGenerator->GetCMakeInstance()->IssueMessage( cmake::FATAL_ERROR, - "Only executables and non-OBJECT libraries may " - "reference target objects.", + "Only executables and libraries may reference target objects.", depender->GetBacktrace()); return; } diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx index cdab671..4716e14 100644 --- a/Source/cmDepends.cxx +++ b/Source/cmDepends.cxx @@ -7,7 +7,6 @@ #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmSystemTools.h" -#include "cmWorkingDirectory.h" #include "cmsys/FStream.hxx" #include <sstream> @@ -15,8 +14,7 @@ #include <utility> cmDepends::cmDepends(cmLocalGenerator* lg, const char* targetDir) - : CompileDirectory() - , LocalGenerator(lg) + : LocalGenerator(lg) , Verbose(false) , FileComparison(nullptr) , TargetDirectory(targetDir) @@ -73,9 +71,6 @@ bool cmDepends::Finalize(std::ostream& /*unused*/, std::ostream& /*unused*/) bool cmDepends::Check(const char* makeFile, const char* internalFile, std::map<std::string, DependencyVector>& validDeps) { - // Dependency checks must be done in proper working directory. - cmWorkingDirectory workdir(this->CompileDirectory); - // Check whether dependencies must be regenerated. bool okay = true; cmsys::ifstream fin(internalFile); diff --git a/Source/cmDepends.h b/Source/cmDepends.h index a4fee3c..4b9e05a 100644 --- a/Source/cmDepends.h +++ b/Source/cmDepends.h @@ -31,9 +31,6 @@ public: path from the build directory to the target file. */ cmDepends(cmLocalGenerator* lg = nullptr, const char* targetDir = ""); - /** at what level will the compile be done from */ - void SetCompileDirectory(const char* dir) { this->CompileDirectory = dir; } - /** Set the local generator for the directory in which we are scanning dependencies. This is not a full local generator; it has been setup to do relative path conversions for the current @@ -95,9 +92,6 @@ protected: virtual bool Finalize(std::ostream& makeDepends, std::ostream& internalDepends); - // The directory in which the build rule for the target file is executed. - std::string CompileDirectory; - // The local generator. cmLocalGenerator* LocalGenerator; diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx index 817b5d9..0ceac85 100644 --- a/Source/cmExportBuildAndroidMKGenerator.cxx +++ b/Source/cmExportBuildAndroidMKGenerator.cxx @@ -41,7 +41,8 @@ void cmExportBuildAndroidMKGenerator::GenerateExpectedTargetsCode( } void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode( - std::ostream& os, const cmGeneratorTarget* target) + std::ostream& os, cmGeneratorTarget const* target, + cmStateEnums::TargetType /*targetType*/) { std::string targetName = this->Namespace; targetName += target->GetExportName(); diff --git a/Source/cmExportBuildAndroidMKGenerator.h b/Source/cmExportBuildAndroidMKGenerator.h index c80839b..a9b6107 100644 --- a/Source/cmExportBuildAndroidMKGenerator.h +++ b/Source/cmExportBuildAndroidMKGenerator.h @@ -11,6 +11,7 @@ #include "cmExportBuildFileGenerator.h" #include "cmExportFileGenerator.h" +#include "cmStateTypes.h" class cmGeneratorTarget; @@ -47,8 +48,9 @@ protected: void GenerateImportHeaderCode(std::ostream& os, const std::string& config = "") override; void GenerateImportFooterCode(std::ostream& os) override; - void GenerateImportTargetCode(std::ostream& os, - const cmGeneratorTarget* target) override; + void GenerateImportTargetCode( + std::ostream& os, cmGeneratorTarget const* target, + cmStateEnums::TargetType /*targetType*/) override; void GenerateExpectedTargetsCode( std::ostream& os, const std::string& expectedTargets) override; void GenerateImportPropertyCode( diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index f7aa6e8..bbbc998 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -59,7 +59,7 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->LG->GetMakefile()->GetBacktrace()); return false; } - if (te->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (this->GetExportTargetType(te) == cmStateEnums::INTERFACE_LIBRARY) { this->GenerateRequiredCMakeVersion(os, "3.0.0"); } } @@ -71,7 +71,7 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) // Create all the imported targets. for (cmGeneratorTarget* gte : this->Exports) { - this->GenerateImportTargetCode(os, gte); + this->GenerateImportTargetCode(os, gte, this->GetExportTargetType(gte)); gte->Target->AppendBuildInterfaceIncludes(); @@ -97,6 +97,15 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) properties, missingTargets); this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte, properties); + + std::string errorMessage; + if (!this->PopulateExportProperties(gte, properties, errorMessage)) { + this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( + cmake::FATAL_ERROR, errorMessage, + this->LG->GetMakefile()->GetBacktrace()); + return false; + } + const bool newCMP0022Behavior = gte->GetPolicyStatusCMP0022() != cmPolicies::WARN && gte->GetPolicyStatusCMP0022() != cmPolicies::OLD; @@ -128,12 +137,13 @@ void cmExportBuildFileGenerator::GenerateImportTargetsConfig( // Collect import properties for this target. ImportPropertyMap properties; - if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { + if (this->GetExportTargetType(target) != cmStateEnums::INTERFACE_LIBRARY) { this->SetImportLocationProperty(config, suffix, target, properties); } if (!properties.empty()) { // Get the rest of the target details. - if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { + if (this->GetExportTargetType(target) != + cmStateEnums::INTERFACE_LIBRARY) { this->SetImportDetailProperties(config, suffix, target, properties, missingTargets); this->SetImportLinkInterface(config, suffix, @@ -153,6 +163,21 @@ void cmExportBuildFileGenerator::GenerateImportTargetsConfig( } } +cmStateEnums::TargetType cmExportBuildFileGenerator::GetExportTargetType( + cmGeneratorTarget const* target) const +{ + cmStateEnums::TargetType targetType = target->GetType(); + // An object library exports as an interface library if we cannot + // tell clients where to find the objects. This is sufficient + // to support transitive usage requirements on other targets that + // use the object library. + if (targetType == cmStateEnums::OBJECT_LIBRARY && + !this->LG->GetGlobalGenerator()->HasKnownObjectFileLocation(nullptr)) { + targetType = cmStateEnums::INTERFACE_LIBRARY; + } + return targetType; +} + void cmExportBuildFileGenerator::SetExportSet(cmExportSet* exportSet) { this->ExportSet = exportSet; diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 6457a77..ada2709 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmExportFileGenerator.h" +#include "cmStateTypes.h" #include <iosfwd> #include <string> @@ -53,6 +54,8 @@ protected: void GenerateImportTargetsConfig( std::ostream& os, const std::string& config, std::string const& suffix, std::vector<std::string>& missingTargets) override; + cmStateEnums::TargetType GetExportTargetType( + cmGeneratorTarget const* target) const; void HandleMissingTarget(std::string& link_libs, std::vector<std::string>& missingTargets, cmGeneratorTarget* depender, diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index c8a727d..655ebe8 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -146,17 +146,6 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args, } if (cmTarget* target = gg->FindTarget(currentTarget)) { - if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { - std::string reason; - if (!this->Makefile->GetGlobalGenerator() - ->HasKnownObjectFileLocation(&reason)) { - std::ostringstream e; - e << "given OBJECT library \"" << currentTarget - << "\" which may not be exported" << reason << "."; - this->SetError(e.str()); - return false; - } - } if (target->GetType() == cmStateEnums::UTILITY) { this->SetError("given custom target \"" + currentTarget + "\" which may not be exported."); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 434abdc..2dcbfa0 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -11,6 +11,8 @@ #include "cmMakefile.h" #include "cmOutputConverter.h" #include "cmPolicies.h" +#include "cmProperty.h" +#include "cmPropertyMap.h" #include "cmStateTypes.h" #include "cmSystemTools.h" #include "cmTarget.h" @@ -901,8 +903,10 @@ void cmExportFileGenerator::GenerateExpectedTargetsCode( "\n\n"; /* clang-format on */ } + void cmExportFileGenerator::GenerateImportTargetCode( - std::ostream& os, const cmGeneratorTarget* target) + std::ostream& os, cmGeneratorTarget const* target, + cmStateEnums::TargetType targetType) { // Construct the imported target name. std::string targetName = this->Namespace; @@ -911,7 +915,7 @@ void cmExportFileGenerator::GenerateImportTargetCode( // Create the imported target. os << "# Create imported target " << targetName << "\n"; - switch (target->GetType()) { + switch (targetType) { case cmStateEnums::EXECUTABLE: os << "add_executable(" << targetName << " IMPORTED)\n"; break; @@ -1095,3 +1099,41 @@ void cmExportFileGenerator::GenerateImportedFileChecksCode( os << ")\n\n"; } + +bool cmExportFileGenerator::PopulateExportProperties( + cmGeneratorTarget* gte, ImportPropertyMap& properties, + std::string& errorMessage) +{ + auto& targetProperties = gte->Target->GetProperties(); + const auto& exportProperties = targetProperties.find("EXPORT_PROPERTIES"); + if (exportProperties != targetProperties.end()) { + std::vector<std::string> propsToExport; + cmSystemTools::ExpandListArgument(exportProperties->second.GetValue(), + propsToExport); + for (auto& prop : propsToExport) { + /* Black list reserved properties */ + if (cmSystemTools::StringStartsWith(prop, "IMPORTED_") || + cmSystemTools::StringStartsWith(prop, "INTERFACE_")) { + std::ostringstream e; + e << "Target \"" << gte->Target->GetName() << "\" contains property \"" + << prop << "\" in EXPORT_PROPERTIES but IMPORTED_* and INTERFACE_* " + << "properties are reserved."; + errorMessage = e.str(); + return false; + } + auto propertyValue = targetProperties.GetPropertyValue(prop); + std::string evaluatedValue = cmGeneratorExpression::Preprocess( + propertyValue, cmGeneratorExpression::StripAllGeneratorExpressions); + if (evaluatedValue != propertyValue) { + std::ostringstream e; + e << "Target \"" << gte->Target->GetName() << "\" contains property \"" + << prop << "\" in EXPORT_PROPERTIES but this property contains a " + << "generator expression. This is not allowed."; + errorMessage = e.str(); + return false; + } + properties[prop] = propertyValue; + } + } + return true; +} diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 985c8f6..954e6c5 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmGeneratorExpression.h" +#include "cmStateTypes.h" #include "cmVersion.h" #include "cmVersionConfig.h" @@ -76,7 +77,8 @@ protected: virtual void GenerateImportFooterCode(std::ostream& os); void GenerateImportVersionCode(std::ostream& os); virtual void GenerateImportTargetCode(std::ostream& os, - cmGeneratorTarget const* target); + cmGeneratorTarget const* target, + cmStateEnums::TargetType targetType); virtual void GenerateImportPropertyCode(std::ostream& os, const std::string& config, cmGeneratorTarget const* target, @@ -166,6 +168,10 @@ protected: virtual void GenerateRequiredCMakeVersion(std::ostream& os, const char* versionString); + bool PopulateExportProperties(cmGeneratorTarget* gte, + ImportPropertyMap& properties, + std::string& errorMessage); + // The namespace in which the exports are placed in the generated file. std::string Namespace; diff --git a/Source/cmExportInstallAndroidMKGenerator.cxx b/Source/cmExportInstallAndroidMKGenerator.cxx index fe565e6..9bc8089 100644 --- a/Source/cmExportInstallAndroidMKGenerator.cxx +++ b/Source/cmExportInstallAndroidMKGenerator.cxx @@ -55,7 +55,8 @@ void cmExportInstallAndroidMKGenerator::GenerateImportFooterCode(std::ostream&) } void cmExportInstallAndroidMKGenerator::GenerateImportTargetCode( - std::ostream& os, const cmGeneratorTarget* target) + std::ostream& os, cmGeneratorTarget const* target, + cmStateEnums::TargetType /*targetType*/) { std::string targetName = this->Namespace; targetName += target->GetExportName(); diff --git a/Source/cmExportInstallAndroidMKGenerator.h b/Source/cmExportInstallAndroidMKGenerator.h index 91554ee..8883ffa 100644 --- a/Source/cmExportInstallAndroidMKGenerator.h +++ b/Source/cmExportInstallAndroidMKGenerator.h @@ -12,6 +12,7 @@ #include "cmExportFileGenerator.h" #include "cmExportInstallFileGenerator.h" +#include "cmStateTypes.h" class cmGeneratorTarget; class cmInstallExportGenerator; @@ -41,8 +42,9 @@ protected: void GenerateImportHeaderCode(std::ostream& os, const std::string& config = "") override; void GenerateImportFooterCode(std::ostream& os) override; - void GenerateImportTargetCode(std::ostream& os, - const cmGeneratorTarget* target) override; + void GenerateImportTargetCode( + std::ostream& os, cmGeneratorTarget const* target, + cmStateEnums::TargetType /*targetType*/) override; void GenerateExpectedTargetsCode( std::ostream& os, const std::string& expectedTargets) override; void GenerateImportPropertyCode( diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 954b561..63d04a6 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -75,11 +75,12 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) // Create all the imported targets. for (cmTargetExport* te : allTargets) { cmGeneratorTarget* gt = te->Target; + cmStateEnums::TargetType targetType = this->GetExportTargetType(te); requiresConfigFiles = - requiresConfigFiles || gt->GetType() != cmStateEnums::INTERFACE_LIBRARY; + requiresConfigFiles || targetType != cmStateEnums::INTERFACE_LIBRARY; - this->GenerateImportTargetCode(os, gt); + this->GenerateImportTargetCode(os, gt, targetType); ImportPropertyMap properties; @@ -103,6 +104,12 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) cmGeneratorExpression::InstallInterface, properties, missingTargets); + std::string errorMessage; + if (!this->PopulateExportProperties(gt, properties, errorMessage)) { + cmSystemTools::Error(errorMessage.c_str()); + return false; + } + const bool newCMP0022Behavior = gt->GetPolicyStatusCMP0022() != cmPolicies::WARN && gt->GetPolicyStatusCMP0022() != cmPolicies::OLD; @@ -114,7 +121,7 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) require2_8_12 = true; } } - if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (targetType == cmStateEnums::INTERFACE_LIBRARY) { require3_0_0 = true; } if (gt->GetProperty("INTERFACE_SOURCES")) { @@ -308,7 +315,7 @@ void cmExportInstallFileGenerator::GenerateImportTargetsConfig( // Add each target in the set to the export. for (cmTargetExport* te : *this->IEGen->GetExportSet()->GetTargetExports()) { // Collect import properties for this target. - if (te->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (this->GetExportTargetType(te) == cmStateEnums::INTERFACE_LIBRARY) { continue; } @@ -426,6 +433,19 @@ void cmExportInstallFileGenerator::SetImportLocationProperty( } } +cmStateEnums::TargetType cmExportInstallFileGenerator::GetExportTargetType( + cmTargetExport const* targetExport) const +{ + cmStateEnums::TargetType targetType = targetExport->Target->GetType(); + // An OBJECT library installed with no OBJECTS DESTINATION + // is transformed to an INTERFACE library. + if (targetType == cmStateEnums::OBJECT_LIBRARY && + targetExport->ObjectsGenerator == nullptr) { + targetType = cmStateEnums::INTERFACE_LIBRARY; + } + return targetType; +} + void cmExportInstallFileGenerator::HandleMissingTarget( std::string& link_libs, std::vector<std::string>& missingTargets, cmGeneratorTarget* depender, cmGeneratorTarget* dependee) diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index cda8433..ea607fb 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmExportFileGenerator.h" +#include "cmStateTypes.h" #include <iosfwd> #include <map> @@ -17,6 +18,7 @@ class cmGeneratorTarget; class cmGlobalGenerator; class cmInstallExportGenerator; class cmInstallTargetGenerator; +class cmTargetExport; /** \class cmExportInstallFileGenerator * \brief Generate a file exporting targets from an install tree. @@ -57,6 +59,8 @@ protected: void GenerateImportTargetsConfig( std::ostream& os, const std::string& config, std::string const& suffix, std::vector<std::string>& missingTargets) override; + cmStateEnums::TargetType GetExportTargetType( + cmTargetExport const* targetExport) const; void HandleMissingTarget(std::string& link_libs, std::vector<std::string>& missingTargets, cmGeneratorTarget* depender, diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index ae8cd37..87648cb 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -33,7 +33,7 @@ bool cmExportTryCompileFileGenerator::GenerateMainFile(std::ostream& os) this->Exports.pop_back(); if (emitted.insert(te).second) { emittedDeps.insert(te); - this->GenerateImportTargetCode(os, te); + this->GenerateImportTargetCode(os, te, te->GetType()); ImportPropertyMap properties; diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx index 4dbaa3f..c7c780c 100644 --- a/Source/cmExtraCodeLiteGenerator.cxx +++ b/Source/cmExtraCodeLiteGenerator.cxx @@ -408,7 +408,6 @@ void cmExtraCodeLiteGenerator::CreateProjectSourceEntries( const std::string& projectPath, const cmMakefile* mf, const std::string& projectType, const std::string& targetName) { - cmXMLWriter& xml(*_xml); FindMatchingHeaderfiles(cFiles, otherFiles); // Create 2 virtual folders: src and include @@ -469,10 +468,14 @@ void cmExtraCodeLiteGenerator::CreateProjectSourceEntries( xml.EndElement(); // ResourceCompiler xml.StartElement("General"); - std::string outputPath = mf->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH"); + std::string outputPath = + mf->GetSafeDefinition("CMAKE_RUNTIME_OUTPUT_DIRECTORY"); + if (outputPath.empty()) { + outputPath = mf->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH"); + } std::string relapath; if (!outputPath.empty()) { - relapath = cmSystemTools::RelativePath(this->WorkspacePath, outputPath); + relapath = cmSystemTools::RelativePath(projectPath, outputPath); xml.Attribute("OutputFile", relapath + "/$(ProjectName)"); } else { xml.Attribute("OutputFile", "$(IntermediateDirectory)/$(ProjectName)"); @@ -635,7 +638,7 @@ std::string cmExtraCodeLiteGenerator::GetBuildCommand( if (generator == "NMake Makefiles" || generator == "Ninja") { ss << make; } else if (generator == "MinGW Makefiles" || generator == "Unix Makefiles") { - ss << make << " -j " << this->CpuCount; + ss << make << " -f$(ProjectPath)/Makefile -j " << this->CpuCount; } if (!targetName.empty()) { ss << " " << targetName; diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index d3dcc01..90b943b 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -160,6 +160,12 @@ bool cmFileCommand::InitialPass(std::vector<std::string> const& args, if (subCommand == "TO_NATIVE_PATH") { return this->HandleCMakePathCommand(args, true); } + if (subCommand == "TOUCH") { + return this->HandleTouchCommand(args, true); + } + if (subCommand == "TOUCH_NOCREATE") { + return this->HandleTouchCommand(args, false); + } if (subCommand == "TIMESTAMP") { return this->HandleTimestampCommand(args); } @@ -751,9 +757,9 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args, } } - std::string output; - bool first = true; - for (; i != args.end(); ++i) { + std::vector<std::string> files; + bool warnFollowedSymlinks = false; + while (i != args.end()) { if (*i == "LIST_DIRECTORIES") { ++i; if (i != args.end()) { @@ -771,103 +777,105 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args, this->SetError("LIST_DIRECTORIES missing bool value."); return false; } - continue; - } - - if (recurse && (*i == "FOLLOW_SYMLINKS")) { + ++i; + if (i == args.end()) { + this->SetError("GLOB requires a glob expression after the bool."); + return false; + } + } else if (*i == "FOLLOW_SYMLINKS") { + if (!recurse) { + this->SetError("FOLLOW_SYMLINKS is not a valid parameter for GLOB."); + return false; + } explicitFollowSymlinks = true; g.RecurseThroughSymlinksOn(); ++i; if (i == args.end()) { this->SetError( - "GLOB_RECURSE requires a glob expression after FOLLOW_SYMLINKS"); + "GLOB_RECURSE requires a glob expression after FOLLOW_SYMLINKS."); return false; } - } - - if (*i == "RELATIVE") { + } else if (*i == "RELATIVE") { ++i; // skip RELATIVE if (i == args.end()) { - this->SetError("GLOB requires a directory after the RELATIVE tag"); + this->SetError("GLOB requires a directory after the RELATIVE tag."); return false; } g.SetRelative(i->c_str()); ++i; if (i == args.end()) { - this->SetError("GLOB requires a glob expression after the directory"); + this->SetError("GLOB requires a glob expression after the directory."); return false; } - } - - cmsys::Glob::GlobMessages globMessages; - if (!cmsys::SystemTools::FileIsFullPath(*i)) { - std::string expr = this->Makefile->GetCurrentSourceDirectory(); - // Handle script mode - if (!expr.empty()) { - expr += "/" + *i; - g.FindFiles(expr, &globMessages); - } else { - g.FindFiles(*i, &globMessages); - } } else { - g.FindFiles(*i, &globMessages); - } - - if (!globMessages.empty()) { - bool shouldExit = false; - for (cmsys::Glob::Message const& globMessage : globMessages) { - if (globMessage.type == cmsys::Glob::cyclicRecursion) { - this->Makefile->IssueMessage( - cmake::AUTHOR_WARNING, - "Cyclic recursion detected while globbing for '" + *i + "':\n" + - globMessage.content); + std::string expr = *i; + if (!cmsys::SystemTools::FileIsFullPath(*i)) { + expr = this->Makefile->GetCurrentSourceDirectory(); + // Handle script mode + if (!expr.empty()) { + expr += "/" + *i; } else { - this->Makefile->IssueMessage( - cmake::FATAL_ERROR, "Error has occurred while globbing for '" + - *i + "' - " + globMessage.content); - shouldExit = true; + expr = *i; } } - if (shouldExit) { - return false; + + cmsys::Glob::GlobMessages globMessages; + g.FindFiles(expr, &globMessages); + + if (!globMessages.empty()) { + bool shouldExit = false; + for (cmsys::Glob::Message const& globMessage : globMessages) { + if (globMessage.type == cmsys::Glob::cyclicRecursion) { + this->Makefile->IssueMessage( + cmake::AUTHOR_WARNING, + "Cyclic recursion detected while globbing for '" + *i + "':\n" + + globMessage.content); + } else { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, "Error has occurred while globbing for '" + + *i + "' - " + globMessage.content); + shouldExit = true; + } + } + if (shouldExit) { + return false; + } } - } - std::vector<std::string>::size_type cc; - std::vector<std::string>& files = g.GetFiles(); - std::sort(files.begin(), files.end()); - for (cc = 0; cc < files.size(); cc++) { - if (!first) { - output += ";"; + if (recurse && !explicitFollowSymlinks && + g.GetFollowedSymlinkCount() != 0) { + warnFollowedSymlinks = true; } - output += files[cc]; - first = false; + + std::vector<std::string>& foundFiles = g.GetFiles(); + files.insert(files.end(), foundFiles.begin(), foundFiles.end()); + ++i; } } - if (recurse && !explicitFollowSymlinks) { - switch (status) { - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::NEW: - // Correct behavior, yay! - break; - case cmPolicies::OLD: - // Probably not really the expected behavior, but the author explicitly - // asked for the old behavior... no warning. - case cmPolicies::WARN: - // Possibly unexpected old behavior *and* we actually traversed - // symlinks without being explicitly asked to: warn the author. - if (g.GetFollowedSymlinkCount() != 0) { - this->Makefile->IssueMessage( - cmake::AUTHOR_WARNING, - cmPolicies::GetPolicyWarning(cmPolicies::CMP0009)); - } - break; - } + switch (status) { + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + // Correct behavior, yay! + break; + case cmPolicies::OLD: + // Probably not really the expected behavior, but the author explicitly + // asked for the old behavior... no warning. + case cmPolicies::WARN: + // Possibly unexpected old behavior *and* we actually traversed + // symlinks without being explicitly asked to: warn the author. + if (warnFollowedSymlinks) { + this->Makefile->IssueMessage( + cmake::AUTHOR_WARNING, + cmPolicies::GetPolicyWarning(cmPolicies::CMP0009)); + } + break; } - this->Makefile->AddDefinition(variable, output.c_str()); + std::sort(files.begin(), files.end()); + files.erase(std::unique(files.begin(), files.end()), files.end()); + this->Makefile->AddDefinition(variable, cmJoin(files, ";").c_str()); return true; } @@ -905,6 +913,38 @@ bool cmFileCommand::HandleMakeDirectoryCommand( return true; } +bool cmFileCommand::HandleTouchCommand(std::vector<std::string> const& args, + bool create) +{ + // File command has at least one argument + assert(args.size() > 1); + + std::vector<std::string>::const_iterator i = args.begin(); + + i++; // Get rid of subcommand + + for (; i != args.end(); ++i) { + std::string tfile = *i; + if (!cmsys::SystemTools::FileIsFullPath(tfile)) { + tfile = this->Makefile->GetCurrentSourceDirectory(); + tfile += "/" + *i; + } + if (!this->Makefile->CanIWriteThisFile(tfile)) { + std::string e = + "attempted to touch a file: " + tfile + " in a source directory."; + this->SetError(e); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + if (!cmSystemTools::Touch(tfile, create)) { + std::string error = "problem touching file: " + tfile; + this->SetError(error); + return false; + } + } + return true; +} + bool cmFileCommand::HandleDifferentCommand( std::vector<std::string> const& args) { diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h index 17269f3..719dca2 100644 --- a/Source/cmFileCommand.h +++ b/Source/cmFileCommand.h @@ -39,6 +39,7 @@ protected: bool HandleHashCommand(std::vector<std::string> const& args); bool HandleStringsCommand(std::vector<std::string> const& args); bool HandleGlobCommand(std::vector<std::string> const& args, bool recurse); + bool HandleTouchCommand(std::vector<std::string> const& args, bool create); bool HandleMakeDirectoryCommand(std::vector<std::string> const& args); bool HandleRelativePathCommand(std::vector<std::string> const& args); diff --git a/Source/cmFileTimeComparison.h b/Source/cmFileTimeComparison.h index b1f8ed6..114989b 100644 --- a/Source/cmFileTimeComparison.h +++ b/Source/cmFileTimeComparison.h @@ -8,9 +8,9 @@ class cmFileTimeComparisonInternal; /** \class cmFileTimeComparison - * \brief Helper class for performing globbing searches. + * \brief Helper class for comparing file modification times. * - * Finds all files that match a given globbing expression. + * Compare file modification times or test if file modification times differ. */ class cmFileTimeComparison { diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx index 417cdd2..865595b 100644 --- a/Source/cmFindBase.cxx +++ b/Source/cmFindBase.cxx @@ -67,8 +67,6 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn) } this->AlreadyInCache = false; - this->SelectDefaultNoPackageRootPath(); - // Find the current root path mode. this->SelectDefaultRootPathMode(); @@ -206,16 +204,12 @@ void cmFindBase::FillPackageRootPath() { cmSearchPath& paths = this->LabeledPaths[PathLabel::PackageRoot]; - // Add package specific search prefixes - // NOTE: This should be using const_reverse_iterator but HP aCC and - // Oracle sunCC both currently have standard library issues - // with the reverse iterator APIs. - for (std::deque<std::string>::reverse_iterator pkg = - this->Makefile->FindPackageModuleStack.rbegin(); - pkg != this->Makefile->FindPackageModuleStack.rend(); ++pkg) { - std::string varName = *pkg + "_ROOT"; - paths.AddCMakePrefixPath(varName); - paths.AddEnvPrefixPath(varName); + // Add the PACKAGE_ROOT_PATH from each enclosing find_package call. + for (std::deque<std::vector<std::string>>::const_reverse_iterator pkgPaths = + this->Makefile->FindPackageRootPathStack.rbegin(); + pkgPaths != this->Makefile->FindPackageRootPathStack.rend(); + ++pkgPaths) { + paths.AddPrefixPaths(*pkgPaths); } paths.AddSuffixes(this->SearchPathSuffixes); @@ -225,8 +219,8 @@ void cmFindBase::FillCMakeVariablePath() { cmSearchPath& paths = this->LabeledPaths[PathLabel::CMake]; - // Add CMake varibles of the same name as the previous environment - // varibles CMAKE_*_PATH to be used most of the time with -D + // Add CMake variables of the same name as the previous environment + // variables CMAKE_*_PATH to be used most of the time with -D // command line options std::string var = "CMAKE_"; var += this->CMakePathName; diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx index 4a467f3..64108d7 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -88,13 +88,6 @@ void cmFindCommon::InitializeSearchPathGroups() std::make_pair(PathLabel::Guess, cmSearchPath(this))); } -void cmFindCommon::SelectDefaultNoPackageRootPath() -{ - if (!this->Makefile->IsOn("__UNDOCUMENTED_CMAKE_FIND_PACKAGE_ROOT")) { - this->NoPackageRootPath = true; - } -} - void cmFindCommon::SelectDefaultRootPathMode() { // Check the policy variable for this find command type. diff --git a/Source/cmFindCommon.h b/Source/cmFindCommon.h index b237f1b..89ff174 100644 --- a/Source/cmFindCommon.h +++ b/Source/cmFindCommon.h @@ -84,9 +84,6 @@ protected: /** Compute final search path list (reroot + trailing slash). */ void ComputeFinalPaths(); - /** Decide whether to enable the PACKAGE_ROOT search entries. */ - void SelectDefaultNoPackageRootPath(); - /** Compute the current default root path mode. */ void SelectDefaultRootPathMode(); diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 2f3a85b..e9ac4a7 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -21,6 +21,7 @@ #include "cmAlgorithms.h" #include "cmMakefile.h" +#include "cmPolicies.h" #include "cmSearchPath.h" #include "cmState.h" #include "cmStateTypes.h" @@ -209,8 +210,6 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args, this->SortDirection = strcmp(sd, "ASC") == 0 ? Asc : Dec; } - this->SelectDefaultNoPackageRootPath(); - // Find the current root path mode. this->SelectDefaultRootPathMode(); @@ -454,6 +453,38 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args, return true; } + { + // Allocate a PACKAGE_ROOT_PATH for the current find_package call. + this->Makefile->FindPackageRootPathStack.emplace_back(); + std::vector<std::string>& rootPaths = + *this->Makefile->FindPackageRootPathStack.rbegin(); + + // Add root paths from <PackageName>_ROOT CMake and environment variables, + // subject to CMP0074. + switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0074)) { + case cmPolicies::WARN: + this->Makefile->MaybeWarnCMP0074(this->Name); + CM_FALLTHROUGH; + case cmPolicies::OLD: + // OLD behavior is to ignore the <pkg>_ROOT variables. + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0074)); + break; + case cmPolicies::NEW: { + // NEW behavior is to honor the <pkg>_ROOT variables. + std::string const rootVar = this->Name + "_ROOT"; + if (const char* pkgRoot = this->Makefile->GetDefinition(rootVar)) { + cmSystemTools::ExpandListArgument(pkgRoot, rootPaths, false); + } + cmSystemTools::GetPath(rootPaths, rootVar.c_str()); + } break; + } + } + this->SetModuleVariables(components); // See if there is a Find<package>.cmake module. @@ -589,9 +620,6 @@ void cmFindPackageCommand::SetModuleVariables(const std::string& components) exact += "_FIND_VERSION_EXACT"; this->AddFindDefinition(exact, this->VersionExact ? "1" : "0"); } - - // Push on to the package stack - this->Makefile->FindPackageModuleStack.push_back(this->Name); } void cmFindPackageCommand::AddFindDefinition(const std::string& var, @@ -1076,7 +1104,7 @@ void cmFindPackageCommand::AppendSuccessInformation() this->RestoreFindDefinitions(); // Pop the package stack - this->Makefile->FindPackageModuleStack.pop_back(); + this->Makefile->FindPackageRootPathStack.pop_back(); } void cmFindPackageCommand::ComputePrefixes() @@ -1116,16 +1144,14 @@ void cmFindPackageCommand::FillPrefixesPackageRoot() { cmSearchPath& paths = this->LabeledPaths[PathLabel::PackageRoot]; - // Add package specific search prefixes - // NOTE: This should be using const_reverse_iterator but HP aCC and - // Oracle sunCC both currently have standard library issues - // with the reverse iterator APIs. - for (std::deque<std::string>::reverse_iterator pkg = - this->Makefile->FindPackageModuleStack.rbegin(); - pkg != this->Makefile->FindPackageModuleStack.rend(); ++pkg) { - std::string varName = *pkg + "_ROOT"; - paths.AddCMakePath(varName); - paths.AddEnvPath(varName); + // Add the PACKAGE_ROOT_PATH from each enclosing find_package call. + for (std::deque<std::vector<std::string>>::const_reverse_iterator pkgPaths = + this->Makefile->FindPackageRootPathStack.rbegin(); + pkgPaths != this->Makefile->FindPackageRootPathStack.rend(); + ++pkgPaths) { + for (std::string const& path : *pkgPaths) { + paths.AddPath(path); + } } } diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h index 92dac79..0561799 100644 --- a/Source/cmGeneratorExpressionEvaluator.h +++ b/Source/cmGeneratorExpressionEvaluator.h @@ -7,6 +7,7 @@ #include <stddef.h> #include <string> +#include <utility> #include <vector> struct cmGeneratorExpressionContext; @@ -64,17 +65,16 @@ private: struct GeneratorExpressionContent : public cmGeneratorExpressionEvaluator { GeneratorExpressionContent(const char* startContent, size_t length); - void SetIdentifier( - std::vector<cmGeneratorExpressionEvaluator*> const& identifier) + + void SetIdentifier(std::vector<cmGeneratorExpressionEvaluator*> identifier) { - this->IdentifierChildren = identifier; + this->IdentifierChildren = std::move(identifier); } void SetParameters( - std::vector<std::vector<cmGeneratorExpressionEvaluator*>> const& - parameters) + std::vector<std::vector<cmGeneratorExpressionEvaluator*>> parameters) { - this->ParamChildren = parameters; + this->ParamChildren = std::move(parameters); } Type GetType() const override diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index c1f1ee4..f444113 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -275,6 +275,62 @@ static const struct EqualNode : public cmGeneratorExpressionNode } } equalNode; +static const struct InListNode : public cmGeneratorExpressionNode +{ + InListNode() {} + + int NumExpectedParameters() const override { return 2; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* /*context*/, + const GeneratorExpressionContent* /*content*/, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + std::vector<std::string> values; + cmSystemTools::ExpandListArgument(parameters[1], values); + if (values.empty()) { + return "0"; + } + + return std::find(values.cbegin(), values.cend(), parameters.front()) == + values.cend() + ? "0" + : "1"; + } +} inListNode; + +static const struct TargetExistsNode : public cmGeneratorExpressionNode +{ + TargetExistsNode() {} + + int NumExpectedParameters() const override { return 1; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + if (parameters.size() != 1) { + reportError(context, content->GetOriginalExpression(), + "$<TARGET_EXISTS:...> expression requires one parameter"); + return std::string(); + } + + std::string targetName = parameters.front(); + if (targetName.empty() || + !cmGeneratorExpression::IsValidTargetName(targetName)) { + reportError(context, content->GetOriginalExpression(), + "$<TARGET_EXISTS:tgt> expression requires a non-empty " + "valid target name."); + return std::string(); + } + + return context->LG->GetMakefile()->FindTargetToUse(targetName) ? "1" : "0"; + } +} targetExistsNode; + static const struct LowerCaseNode : public cmGeneratorExpressionNode { LowerCaseNode() {} @@ -1827,6 +1883,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( nodeMap["TARGET_BUNDLE_CONTENT_DIR"] = &targetBundleContentDirNode; nodeMap["STREQUAL"] = &strEqualNode; nodeMap["EQUAL"] = &equalNode; + nodeMap["IN_LIST"] = &inListNode; nodeMap["LOWER_CASE"] = &lowerCaseNode; nodeMap["UPPER_CASE"] = &upperCaseNode; nodeMap["MAKE_C_IDENTIFIER"] = &makeCIdentifierNode; @@ -1839,6 +1896,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( nodeMap["TARGET_NAME"] = &targetNameNode; nodeMap["TARGET_OBJECTS"] = &targetObjectsNode; nodeMap["TARGET_POLICY"] = &targetPolicyNode; + nodeMap["TARGET_EXISTS"] = &targetExistsNode; nodeMap["BUILD_INTERFACE"] = &buildInterfaceNode; nodeMap["INSTALL_INTERFACE"] = &installInterfaceNode; nodeMap["INSTALL_PREFIX"] = &installPrefixNode; diff --git a/Source/cmGeneratorExpressionParser.cxx b/Source/cmGeneratorExpressionParser.cxx index 278de04..7b4dc7b 100644 --- a/Source/cmGeneratorExpressionParser.cxx +++ b/Source/cmGeneratorExpressionParser.cxx @@ -6,6 +6,7 @@ #include <assert.h> #include <stddef.h> +#include <utility> cmGeneratorExpressionParser::cmGeneratorExpressionParser( const std::vector<cmGeneratorExpressionToken>& tokens) @@ -92,7 +93,7 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression( assert(this->it != this->Tokens.end()); ++this->it; --this->NestingLevel; - content->SetIdentifier(identifier); + content->SetIdentifier(std::move(identifier)); result.push_back(content); return; } @@ -198,8 +199,8 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression( ((this->it - 1)->Content - startToken->Content) + (this->it - 1)->Length; GeneratorExpressionContent* content = new GeneratorExpressionContent(startToken->Content, contentLength); - content->SetIdentifier(identifier); - content->SetParameters(parameters); + content->SetIdentifier(std::move(identifier)); + content->SetParameters(std::move(parameters)); result.push_back(content); } diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 2bb01b2..63bfbc6 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -132,8 +132,8 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) this->SourceEntries, true); this->DLLPlatform = - (this->Makefile->IsOn("WIN32") || this->Makefile->IsOn("CYGWIN") || - this->Makefile->IsOn("MINGW")); + strcmp(this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), + "") != 0; this->PolicyMap = t->PolicyMap; } @@ -240,13 +240,16 @@ const char* cmGeneratorTarget::GetOutputTargetType( case cmStateEnums::MODULE_LIBRARY: switch (artifact) { case cmStateEnums::RuntimeBinaryArtifact: - // Module import libraries are treated as archive targets. + // Module libraries are always treated as library targets. return "LIBRARY"; case cmStateEnums::ImportLibraryArtifact: - // Module libraries are always treated as library targets. + // Module import libraries are treated as archive targets. return "ARCHIVE"; } break; + case cmStateEnums::OBJECT_LIBRARY: + // Object libraries are always treated as object targets. + return "OBJECT"; case cmStateEnums::EXECUTABLE: switch (artifact) { case cmStateEnums::RuntimeBinaryArtifact: @@ -808,6 +811,26 @@ static void AddInterfaceEntries( } } +static void AddObjectEntries( + cmGeneratorTarget const* thisTarget, std::string const& config, + std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries) +{ + if (cmLinkImplementationLibraries const* impl = + thisTarget->GetLinkImplementationLibraries(config)) { + for (cmLinkImplItem const& lib : impl->Libraries) { + if (lib.Target && + lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { + std::string genex = "$<TARGET_OBJECTS:" + lib + ">"; + cmGeneratorExpression ge(lib.Backtrace); + std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex); + cge->SetEvaluateForBuildsystem(true); + entries.push_back( + new cmGeneratorTarget::TargetPropertyEntry(std::move(cge), lib)); + } + } + } +} + static bool processSources( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, @@ -848,13 +871,10 @@ static bool processSources( std::ostringstream err; if (!targetName.empty()) { err << "Target \"" << targetName - << "\" contains relative " - "path in its INTERFACE_SOURCES:\n" - " \"" + << "\" contains relative path in its INTERFACE_SOURCES:\n \"" << src << "\""; } else { - err << "Found relative path while evaluating sources of " - "\"" + err << "Found relative path while evaluating sources of \"" << tgt->GetName() << "\":\n \"" << src << "\"\n"; } tgt->GetLocalGenerator()->IssueMessage(cmake::FATAL_ERROR, err.str()); @@ -931,23 +951,32 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<std::string>& files, processSources(this, this->SourceEntries, files, uniqueSrcs, &dagChecker, config, debugSources); + // Collect INTERFACE_SOURCES of all direct link-dependencies. std::vector<cmGeneratorTarget::TargetPropertyEntry*> linkInterfaceSourcesEntries; - AddInterfaceEntries(this, config, "INTERFACE_SOURCES", linkInterfaceSourcesEntries); - std::vector<std::string>::size_type numFilesBefore = files.size(); bool contextDependentInterfaceSources = processSources(this, linkInterfaceSourcesEntries, files, uniqueSrcs, &dagChecker, config, debugSources); + // Collect TARGET_OBJECTS of direct object link-dependencies. + std::vector<cmGeneratorTarget::TargetPropertyEntry*> linkObjectsEntries; + AddObjectEntries(this, config, linkObjectsEntries); + std::vector<std::string>::size_type numFilesBefore2 = files.size(); + bool contextDependentObjects = + processSources(this, linkObjectsEntries, files, uniqueSrcs, &dagChecker, + config, debugSources); + if (!contextDependentDirectSources && - !(contextDependentInterfaceSources && numFilesBefore < files.size())) { + !(contextDependentInterfaceSources && numFilesBefore < files.size()) && + !(contextDependentObjects && numFilesBefore2 < files.size())) { this->LinkImplementationLanguageIsContextDependent = false; } cmDeleteAll(linkInterfaceSourcesEntries); + cmDeleteAll(linkObjectsEntries); } void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files, @@ -1053,9 +1082,6 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, kind = SourceKindHeader; } else if (sf->GetPropertyAsBool("EXTERNAL_OBJECT")) { kind = SourceKindExternalObject; - if (this->GetType() == cmStateEnums::OBJECT_LIBRARY) { - badObjLib.push_back(sf); - } } else if (!sf->GetLanguage().empty()) { kind = SourceKindObjectSource; } else if (ext == "def") { @@ -1673,6 +1699,7 @@ bool cmGeneratorTarget::HaveWellDefinedOutputFiles() const return this->GetType() == cmStateEnums::STATIC_LIBRARY || this->GetType() == cmStateEnums::SHARED_LIBRARY || this->GetType() == cmStateEnums::MODULE_LIBRARY || + this->GetType() == cmStateEnums::OBJECT_LIBRARY || this->GetType() == cmStateEnums::EXECUTABLE; } @@ -2001,8 +2028,13 @@ void cmGeneratorTarget::ComputeModuleDefinitionInfo( info.WindowsExportAllSymbols = this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") && this->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS"); +#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE) info.DefFileGenerated = info.WindowsExportAllSymbols || info.Sources.size() > 1; +#else + // Our __create_def helper is only available on Windows. + info.DefFileGenerated = false; +#endif if (info.DefFileGenerated) { info.DefFile = this->ObjectDirectory /* has slash */ + "exports.def"; } else if (!info.Sources.empty()) { @@ -2592,13 +2624,20 @@ std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories( return includes; } +enum class OptionsParse +{ + None, + Shell +}; + static void processCompileOptionsInternal( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, std::vector<std::string>& options, std::unordered_set<std::string>& uniqueOptions, cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, - bool debugOptions, const char* logName, std::string const& language) + bool debugOptions, const char* logName, std::string const& language, + OptionsParse parse) { for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) { std::vector<std::string> entryOptions; @@ -2609,7 +2648,12 @@ static void processCompileOptionsInternal( std::string usedOptions; for (std::string const& opt : entryOptions) { if (uniqueOptions.insert(opt).second) { - options.push_back(opt); + if (parse == OptionsParse::Shell && + cmHasLiteralPrefix(opt, "SHELL:")) { + cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, options); + } else { + options.push_back(opt); + } if (debugOptions) { usedOptions += " * " + opt + "\n"; } @@ -2634,7 +2678,7 @@ static void processCompileOptions( { processCompileOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker, config, debugOptions, "options", - language); + language, OptionsParse::Shell); } void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result, @@ -2688,7 +2732,7 @@ static void processCompileFeatures( { processCompileOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker, config, debugOptions, "features", - std::string()); + std::string(), OptionsParse::None); } void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result, @@ -2738,7 +2782,7 @@ static void processCompileDefinitions( { processCompileOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker, config, debugOptions, - "definitions", language); + "definitions", language, OptionsParse::None); } void cmGeneratorTarget::GetCompileDefinitions( @@ -5325,20 +5369,6 @@ cmGeneratorTarget* cmGeneratorTarget::FindTargetToLink( tgt = nullptr; } - if (tgt && tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) { - std::ostringstream e; - e << "Target \"" << this->GetName() << "\" links to " - "OBJECT library \"" - << tgt->GetName() - << "\" but this is not " - "allowed. " - "One may link only to STATIC or SHARED libraries, or to executables " - "with the ENABLE_EXPORTS property set."; - cmake* cm = this->LocalGenerator->GetCMakeInstance(); - cm->IssueMessage(cmake::FATAL_ERROR, e.str(), this->GetBacktrace()); - tgt = nullptr; - } - return tgt; } @@ -5402,6 +5432,7 @@ bool cmGeneratorTarget::IsLinkable() const this->GetType() == cmStateEnums::SHARED_LIBRARY || this->GetType() == cmStateEnums::MODULE_LIBRARY || this->GetType() == cmStateEnums::UNKNOWN_LIBRARY || + this->GetType() == cmStateEnums::OBJECT_LIBRARY || this->GetType() == cmStateEnums::INTERFACE_LIBRARY || this->IsExecutableWithExports()); } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index c805b98..f9eb90f 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -6,11 +6,11 @@ #include "cmsys/FStream.hxx" #include <algorithm> #include <assert.h> +#include <cstring> #include <iterator> #include <sstream> #include <stdio.h> #include <stdlib.h> -#include <string.h> #if defined(_WIN32) && !defined(__CYGWIN__) #include <windows.h> @@ -1806,6 +1806,8 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/, cmSystemTools::OutputOption outputflag, std::vector<std::string> const& nativeOptions) { + bool hideconsole = cmSystemTools::GetRunCommandHideConsole(); + /** * Run an executable command and put the stdout in output. */ @@ -1813,9 +1815,17 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/, output += "Change Dir: "; output += bindir; output += "\n"; + if (workdir.Failed()) { + cmSystemTools::SetRunCommandHideConsole(hideconsole); + cmSystemTools::Error("Failed to change directory: ", + std::strerror(workdir.GetLastResult())); + output += "Failed to change directory: "; + output += std::strerror(workdir.GetLastResult()); + output += "\n"; + return 1; + } int retVal; - bool hideconsole = cmSystemTools::GetRunCommandHideConsole(); cmSystemTools::SetRunCommandHideConsole(true); std::string outputBuffer; std::string* outputPtr = &outputBuffer; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index b251f86..55a403e 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -1223,11 +1223,13 @@ void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os) for (std::string const& file : files) { knownDependencies.insert(this->ConvertToNinjaPath(file)); } - // get list files which are implicit dependencies as well and will be phony - // for rebuild manifest - std::vector<std::string> const& lf = lg->GetMakefile()->GetListFiles(); - for (std::string const& j : lf) { - knownDependencies.insert(this->ConvertToNinjaPath(j)); + if (!this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) { + // get list files which are implicit dependencies as well and will be + // phony for rebuild manifest + std::vector<std::string> const& lf = lg->GetMakefile()->GetListFiles(); + for (std::string const& j : lf) { + knownDependencies.insert(this->ConvertToNinjaPath(j)); + } } std::vector<cmGeneratorExpressionEvaluationFile*> const& ef = lg->GetMakefile()->GetEvaluationFiles(); @@ -1335,6 +1337,9 @@ void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os) void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) { + if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) { + return; + } cmLocalGenerator* lg = this->LocalGenerators[0]; std::ostringstream cmd; @@ -1384,8 +1389,14 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) /*explicitDeps=*/cmNinjaDeps(), implicitDeps, /*orderOnlyDeps=*/cmNinjaDeps(), variables); + cmNinjaDeps missingInputs; + std::set_difference(std::make_move_iterator(implicitDeps.begin()), + std::make_move_iterator(implicitDeps.end()), + CustomCommandOutputs.begin(), CustomCommandOutputs.end(), + std::back_inserter(missingInputs)); + this->WritePhonyBuild(os, "A missing CMake input file is not an error.", - implicitDeps, cmNinjaDeps()); + missingInputs, cmNinjaDeps()); } std::string cmGlobalNinjaGenerator::ninjaCmd() const diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index d990a6c..c92df55 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -241,6 +241,10 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2() lg->WriteMakeRule(makefileStream, "The main recursive preinstall target", "preinstall", depends, no_commands, true); + // Write an empty clean: + lg->WriteMakeRule(makefileStream, "The main recursive clean target", "clean", + depends, no_commands, true); + // Write out the "special" stuff lg->WriteSpecialTargetsTop(makefileStream); @@ -256,6 +260,10 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2() void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() { + if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) { + return; + } + // Open the output file. This should not be copy-if-different // because the check-build-system step compares the makefile time to // see if the build system must be regenerated. @@ -525,7 +533,10 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules( std::vector<std::string> depends; std::vector<std::string> commands; - depends.push_back("cmake_check_build_system"); + bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION"); + if (regenerate) { + depends.push_back("cmake_check_build_system"); + } // write the target convenience rules for (cmLocalGenerator* localGen : this->LocalGenerators) { @@ -558,7 +569,9 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules( tmp += "Makefile2"; commands.push_back(lg->GetRecursiveMakeCall(tmp.c_str(), name)); depends.clear(); - depends.push_back("cmake_check_build_system"); + if (regenerate) { + depends.push_back("cmake_check_build_system"); + } lg->WriteMakeRule(ruleFileStream, "Build rule for target.", name, depends, commands, true); @@ -609,7 +622,10 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( // write the directory level rules for this local gen this->WriteDirectoryRules2(ruleFileStream, lg); - depends.push_back("cmake_check_build_system"); + bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION"); + if (regenerate) { + depends.push_back("cmake_check_build_system"); + } // for each target Generate the rule files for each target. const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets(); @@ -715,7 +731,9 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( commands.push_back(progCmd.str()); } depends.clear(); - depends.push_back("cmake_check_build_system"); + if (regenerate) { + depends.push_back("cmake_check_build_system"); + } localName = lg->GetRelativeTargetDirectory(gtarget); localName += "/rule"; lg->WriteMakeRule(ruleFileStream, @@ -898,7 +916,9 @@ void cmGlobalUnixMakefileGenerator3::WriteHelpRule( "for this Makefile:"); lg->AppendEcho(commands, "... all (the default if no target is provided)"); lg->AppendEcho(commands, "... clean"); - lg->AppendEcho(commands, "... depend"); + if (!this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) { + lg->AppendEcho(commands, "... depend"); + } // Keep track of targets already listed. std::set<std::string> emittedTargets; diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 73a5dae..205e0d0 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -636,126 +636,89 @@ bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf) cmsys::ofstream fout(vcxprojAbs.c_str()); cmXMLWriter xw(fout); - /* clang-format off */ - xw.StartDocument(); - xw.StartElement("Project"); - xw.Attribute("DefaultTargets", "Build"); - xw.Attribute("ToolsVersion", "4.0"); - xw.Attribute("xmlns", - "http://schemas.microsoft.com/developer/msbuild/2003"); - if (this->IsNsightTegra()) { - xw.StartElement("PropertyGroup"); - xw.Attribute("Label", "NsightTegraProject"); - xw.StartElement("NsightTegraProjectRevisionNumber"); - xw.Content("6"); - xw.EndElement(); // NsightTegraProjectRevisionNumber - xw.EndElement(); // PropertyGroup - } - xw.StartElement("ItemGroup"); - xw.Attribute("Label", "ProjectConfigurations"); - xw.StartElement("ProjectConfiguration"); - xw.Attribute("Include", "Debug|" + this->GetPlatformName()); - xw.StartElement("Configuration"); - xw.Content("Debug"); - xw.EndElement(); // Configuration - xw.StartElement("Platform"); - xw.Content(this->GetPlatformName()); - xw.EndElement(); // Platform - xw.EndElement(); // ProjectConfiguration - xw.EndElement(); // ItemGroup - xw.StartElement("PropertyGroup"); - xw.Attribute("Label", "Globals"); - xw.StartElement("ProjectGuid"); - xw.Content("{F3FC6D86-508D-3FB1-96D2-995F08B142EC}"); - xw.EndElement(); // ProjectGuid - xw.StartElement("Keyword"); - xw.Content("Win32Proj"); - xw.EndElement(); // Keyword - xw.StartElement("Platform"); - xw.Content(this->GetPlatformName()); - xw.EndElement(); // Platform - if (this->GetSystemName() == "WindowsPhone") { - xw.StartElement("ApplicationType"); - xw.Content("Windows Phone"); - xw.EndElement(); // ApplicationType - xw.StartElement("ApplicationTypeRevision"); - xw.Content(this->GetSystemVersion()); - xw.EndElement(); // ApplicationTypeRevision - } else if (this->GetSystemName() == "WindowsStore") { - xw.StartElement("ApplicationType"); - xw.Content("Windows Store"); - xw.EndElement(); // ApplicationType - xw.StartElement("ApplicationTypeRevision"); - xw.Content(this->GetSystemVersion()); - xw.EndElement(); // ApplicationTypeRevision - } - if (!this->WindowsTargetPlatformVersion.empty()) { - xw.StartElement("WindowsTargetPlatformVersion"); - xw.Content(this->WindowsTargetPlatformVersion); - xw.EndElement(); // WindowsTargetPlatformVersion - } - if (this->GetPlatformName() == "ARM64") { - xw.StartElement("WindowsSDKDesktopARM64Support"); - xw.Content("true"); - xw.EndElement(); // WindowsSDK64DesktopARMSupport - } - else if (this->GetPlatformName() == "ARM") { - xw.StartElement("WindowsSDKDesktopARMSupport"); - xw.Content("true"); - xw.EndElement(); // WindowsSDKDesktopARMSupport - } - xw.EndElement(); // PropertyGroup - xw.StartElement("Import"); - xw.Attribute("Project", - "$(VCTargetsPath)\\Microsoft.Cpp.Default.props"); - xw.EndElement(); // Import + cmXMLDocument doc(xw); + cmXMLElement eprj(doc, "Project"); + eprj.Attribute("DefaultTargets", "Build"); + eprj.Attribute("ToolsVersion", "4.0"); + eprj.Attribute("xmlns", + "http://schemas.microsoft.com/developer/msbuild/2003"); + if (this->IsNsightTegra()) { + cmXMLElement epg(eprj, "PropertyGroup"); + epg.Attribute("Label", "NsightTegraProject"); + cmXMLElement(epg, "NsightTegraProjectRevisionNumber").Content("6"); + } + { + cmXMLElement eig(eprj, "ItemGroup"); + eig.Attribute("Label", "ProjectConfigurations"); + cmXMLElement epc(eig, "ProjectConfiguration"); + epc.Attribute("Include", "Debug|" + this->GetPlatformName()); + cmXMLElement(epc, "Configuration").Content("Debug"); + cmXMLElement(epc, "Platform").Content(this->GetPlatformName()); + } + { + cmXMLElement epg(eprj, "PropertyGroup"); + epg.Attribute("Label", "Globals"); + cmXMLElement(epg, "ProjectGuid") + .Content("{F3FC6D86-508D-3FB1-96D2-995F08B142EC}"); + cmXMLElement(epg, "Keyword").Content("Win32Proj"); + cmXMLElement(epg, "Platform").Content(this->GetPlatformName()); + if (this->GetSystemName() == "WindowsPhone") { + cmXMLElement(epg, "ApplicationType").Content("Windows Phone"); + cmXMLElement(epg, "ApplicationTypeRevision") + .Content(this->GetSystemVersion()); + } else if (this->GetSystemName() == "WindowsStore") { + cmXMLElement(epg, "ApplicationType").Content("Windows Store"); + cmXMLElement(epg, "ApplicationTypeRevision") + .Content(this->GetSystemVersion()); + } + if (!this->WindowsTargetPlatformVersion.empty()) { + cmXMLElement(epg, "WindowsTargetPlatformVersion") + .Content(this->WindowsTargetPlatformVersion); + } + if (this->GetPlatformName() == "ARM64") { + cmXMLElement(epg, "WindowsSDKDesktopARM64Support").Content("true"); + } else if (this->GetPlatformName() == "ARM") { + cmXMLElement(epg, "WindowsSDKDesktopARMSupport").Content("true"); + } + } + cmXMLElement(eprj, "Import") + .Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.Default.props"); if (!this->GeneratorToolsetHostArchitecture.empty()) { - xw.StartElement("PropertyGroup"); - xw.StartElement("PreferredToolArchitecture"); - xw.Content(this->GeneratorToolsetHostArchitecture); - xw.EndElement(); // PreferredToolArchitecture - xw.EndElement(); // PropertyGroup + cmXMLElement epg(eprj, "PropertyGroup"); + cmXMLElement(epg, "PreferredToolArchitecture") + .Content(this->GeneratorToolsetHostArchitecture); } - xw.StartElement("PropertyGroup"); - xw.Attribute("Label", "Configuration"); - xw.StartElement("ConfigurationType"); + { + cmXMLElement epg(eprj, "PropertyGroup"); + epg.Attribute("Label", "Configuration"); + { + cmXMLElement ect(epg, "ConfigurationType"); + if (this->IsNsightTegra()) { + // Tegra-Android platform does not understand "Utility". + ect.Content("StaticLibrary"); + } else { + ect.Content("Utility"); + } + } + cmXMLElement(epg, "CharacterSet").Content("MultiByte"); if (this->IsNsightTegra()) { - // Tegra-Android platform does not understand "Utility". - xw.Content("StaticLibrary"); + cmXMLElement(epg, "NdkToolchainVersion") + .Content(this->GetPlatformToolsetString()); } else { - xw.Content("Utility"); + cmXMLElement(epg, "PlatformToolset") + .Content(this->GetPlatformToolsetString()); } - xw.EndElement(); // ConfigurationType - xw.StartElement("CharacterSet"); - xw.Content("MultiByte"); - xw.EndElement(); // CharacterSet - if (this->IsNsightTegra()) { - xw.StartElement("NdkToolchainVersion"); - xw.Content(this->GetPlatformToolsetString()); - xw.EndElement(); // NdkToolchainVersion - } else { - xw.StartElement("PlatformToolset"); - xw.Content(this->GetPlatformToolsetString()); - xw.EndElement(); // PlatformToolset - } - xw.EndElement(); // PropertyGroup - xw.StartElement("Import"); - xw.Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props"); - xw.EndElement(); // Import - xw.StartElement("ItemDefinitionGroup"); - xw.StartElement("PostBuildEvent"); - xw.StartElement("Command"); - xw.Content("echo VCTargetsPath=$(VCTargetsPath)"); - xw.EndElement(); // Command - xw.EndElement(); // PostBuildEvent - xw.EndElement(); // ItemDefinitionGroup - xw.StartElement("Import"); - xw.Attribute("Project", - "$(VCTargetsPath)\\Microsoft.Cpp.targets"); - xw.EndElement(); // Import - xw.EndElement(); // Project - xw.EndDocument(); - /* clang-format on */ + } + cmXMLElement(eprj, "Import") + .Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props"); + { + cmXMLElement eidg(eprj, "ItemDefinitionGroup"); + cmXMLElement epbe(eidg, "PostBuildEvent"); + cmXMLElement(epbe, "Command") + .Content("echo VCTargetsPath=$(VCTargetsPath)"); + } + cmXMLElement(eprj, "Import") + .Attribute("Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets"); } std::vector<std::string> cmd; diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index ab8ad70..87804ff 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -217,7 +217,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() cmMakefile* mf = lg->GetMakefile(); // Skip the target if no regeneration is to be done. - if (mf->IsOn("CMAKE_SUPPRESS_REGENERATION")) { + if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) { return false; } diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index a4570e1..fa7dc51 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -737,26 +737,24 @@ bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly( bool cmGlobalVisualStudioGenerator::TargetIsCSharpOnly( cmGeneratorTarget const* gt) { - // check to see if this is a C# build - std::set<std::string> languages; - { - // Issue diagnostic if the source files depend on the config. - std::vector<cmSourceFile*> sources; - if (!gt->GetConfigCommonSourceFiles(sources)) { - return false; - } - // Only "real" targets are allowed to be C# targets. - if (gt->Target->GetType() > cmStateEnums::OBJECT_LIBRARY) { - return false; - } + // C# targets can be defined with add_library() (using SHARED or STATIC) and + // also using add_executable(). We do not treat imported C# targets the same + // (these come in as UTILITY) + if (gt->GetType() != cmStateEnums::SHARED_LIBRARY && + gt->GetType() != cmStateEnums::STATIC_LIBRARY && + gt->GetType() != cmStateEnums::EXECUTABLE) { + return false; } - gt->GetLanguages(languages, ""); - if (languages.size() == 1) { - if (*languages.begin() == "CSharp") { - return true; - } + + // Issue diagnostic if the source files depend on the config. + std::vector<cmSourceFile*> sources; + if (!gt->GetConfigCommonSourceFiles(sources)) { + return false; } - return false; + + std::set<std::string> languages; + gt->GetLanguages(languages, ""); + return languages.size() == 1 && languages.count("CSharp") > 0; } bool cmGlobalVisualStudioGenerator::TargetCanBeReferenced( diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 8f61071..f8597af 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -458,7 +458,7 @@ void cmGlobalXCodeGenerator::AddExtraTargets( makeHelper.push_back(""); // placeholder, see below // Add ZERO_CHECK - bool regenerate = !mf->IsOn("CMAKE_SUPPRESS_REGENERATION"); + bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION"); bool generateTopLevelProjectOnly = mf->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY"); bool isTopLevel = @@ -466,7 +466,7 @@ void cmGlobalXCodeGenerator::AddExtraTargets( if (regenerate && (isTopLevel || !generateTopLevelProjectOnly)) { this->CreateReRunCMakeFile(root, gens); std::string file = - this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile.c_str()); + this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile); cmSystemTools::ReplaceString(file, "\\ ", " "); cmTarget* check = mf->AddUtilityCommand( CMAKE_CHECK_BUILD_SYSTEM_TARGET, cmMakefile::TargetOrigin::Generator, @@ -553,7 +553,7 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile( for (const auto& lfile : lfiles) { makefileStream << "TARGETS += $(subst $(space),$(spaceplus),$(wildcard " - << this->ConvertToRelativeForMake(lfile.c_str()) << "))\n"; + << this->ConvertToRelativeForMake(lfile) << "))\n"; } std::string checkCache = root->GetBinaryDirectory(); @@ -562,11 +562,11 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile( checkCache += "cmake.check_cache"; makefileStream << "\n" - << this->ConvertToRelativeForMake(checkCache.c_str()) + << this->ConvertToRelativeForMake(checkCache) << ": $(TARGETS)\n"; makefileStream << "\t" << this->ConvertToRelativeForMake( - cmSystemTools::GetCMakeCommand().c_str()) + cmSystemTools::GetCMakeCommand()) << " -H" << this->ConvertToRelativeForMake(root->GetSourceDirectory()) << " -B" @@ -1571,12 +1571,11 @@ void cmGlobalXCodeGenerator::AddCommandsToBuildPhase( } std::string cdir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory(); - cdir = this->ConvertToRelativeForMake(cdir.c_str()); + cdir = this->ConvertToRelativeForMake(cdir); std::string makecmd = "make -C "; makecmd += cdir; makecmd += " -f "; - makecmd += - this->ConvertToRelativeForMake((makefile + "$CONFIGURATION").c_str()); + makecmd += this->ConvertToRelativeForMake((makefile + "$CONFIGURATION")); makecmd += " all"; buildphase->AddAttribute("shellScript", this->CreateString(makecmd)); buildphase->AddAttribute("showEnvVarsInLog", this->CreateString("0")); @@ -1611,8 +1610,7 @@ void cmGlobalXCodeGenerator::CreateCustomRulesMakefile( const std::vector<std::string>& outputs = ccg.GetOutputs(); if (!outputs.empty()) { for (auto const& output : outputs) { - makefileStream << "\\\n\t" - << this->ConvertToRelativeForMake(output.c_str()); + makefileStream << "\\\n\t" << this->ConvertToRelativeForMake(output); } } else { std::ostringstream str; @@ -1633,8 +1631,7 @@ void cmGlobalXCodeGenerator::CreateCustomRulesMakefile( // There is at least one output, start the rule for it const char* sep = ""; for (auto const& output : outputs) { - makefileStream << sep - << this->ConvertToRelativeForMake(output.c_str()); + makefileStream << sep << this->ConvertToRelativeForMake(output); sep = " "; } makefileStream << ": "; @@ -1646,8 +1643,7 @@ void cmGlobalXCodeGenerator::CreateCustomRulesMakefile( std::string dep; if (this->CurrentLocalGenerator->GetRealDependency(d, configName, dep)) { - makefileStream << "\\\n" - << this->ConvertToRelativeForMake(dep.c_str()); + makefileStream << "\\\n" << this->ConvertToRelativeForMake(dep); } } makefileStream << "\n"; @@ -1664,12 +1660,12 @@ void cmGlobalXCodeGenerator::CreateCustomRulesMakefile( // Build the command line in a single string. std::string cmd2 = ccg.GetCommand(c); cmSystemTools::ReplaceString(cmd2, "/./", "/"); - cmd2 = this->ConvertToRelativeForMake(cmd2.c_str()); + cmd2 = this->ConvertToRelativeForMake(cmd2); std::string cmd; std::string wd = ccg.GetWorkingDirectory(); if (!wd.empty()) { cmd += "cd "; - cmd += this->ConvertToRelativeForMake(wd.c_str()); + cmd += this->ConvertToRelativeForMake(wd); cmd += " && "; } cmd += cmd2; @@ -3193,7 +3189,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( gt->GetType() == cmStateEnums::SHARED_LIBRARY || gt->GetType() == cmStateEnums::MODULE_LIBRARY) { std::string tfull = gt->GetFullPath(configName); - std::string trel = this->ConvertToRelativeForMake(tfull.c_str()); + std::string trel = this->ConvertToRelativeForMake(tfull); // Add this target to the post-build phases of its dependencies. std::map<std::string, cmXCodeObject::StringVec>::const_iterator y = @@ -3221,7 +3217,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( target->GetDependLibraries().find(configName); if (x != target->GetDependLibraries().end()) { for (auto const& deplib : x->second) { - std::string file = this->ConvertToRelativeForMake(deplib.c_str()); + std::string file = this->ConvertToRelativeForMake(deplib); makefileStream << "\\\n\t" << file; dummyRules.insert(file); } @@ -3236,7 +3232,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( d += objLibName; d += ".a"; - std::string dependency = this->ConvertToRelativeForMake(d.c_str()); + std::string dependency = this->ConvertToRelativeForMake(d); makefileStream << "\\\n\t" << dependency; dummyRules.insert(dependency); } @@ -3244,8 +3240,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( // Write the action to remove the target if it is out of date. makefileStream << "\n"; makefileStream << "\t/bin/rm -f " - << this->ConvertToRelativeForMake(tfull.c_str()) - << "\n"; + << this->ConvertToRelativeForMake(tfull) << "\n"; // if building for more than one architecture // then remove those executables as well if (this->Architectures.size() > 1) { @@ -3257,8 +3252,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget( universalFile += "/"; universalFile += gt->GetFullName(configName); makefileStream << "\t/bin/rm -f " - << this->ConvertToRelativeForMake( - universalFile.c_str()) + << this->ConvertToRelativeForMake(universalFile) << "\n"; } } diff --git a/Source/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx index 354b757..f996788 100644 --- a/Source/cmIDEOptions.cxx +++ b/Source/cmIDEOptions.cxx @@ -25,7 +25,7 @@ cmIDEOptions::~cmIDEOptions() { } -void cmIDEOptions::HandleFlag(const char* flag) +void cmIDEOptions::HandleFlag(std::string const& flag) { // If the last option was -D then this option is the definition. if (this->DoingDefine) { @@ -49,26 +49,27 @@ void cmIDEOptions::HandleFlag(const char* flag) } // Look for known arguments. - if (flag[0] == '-' || (this->AllowSlash && flag[0] == '/')) { + size_t len = flag.length(); + if (len > 0 && (flag[0] == '-' || (this->AllowSlash && flag[0] == '/'))) { // Look for preprocessor definitions. - if (this->AllowDefine && flag[1] == 'D') { - if (flag[2] == '\0') { + if (this->AllowDefine && len > 1 && flag[1] == 'D') { + if (len <= 2) { // The next argument will have the definition. this->DoingDefine = true; } else { // Store this definition. - this->Defines.push_back(flag + 2); + this->Defines.push_back(flag.substr(2)); } return; } // Look for include directory. - if (this->AllowInclude && flag[1] == 'I') { - if (flag[2] == '\0') { + if (this->AllowInclude && len > 1 && flag[1] == 'I') { + if (len <= 2) { // The next argument will have the include directory. this->DoingInclude = true; } else { // Store this include directory. - this->Includes.push_back(flag + 2); + this->Includes.push_back(flag.substr(2)); } return; } @@ -92,8 +93,9 @@ void cmIDEOptions::HandleFlag(const char* flag) } bool cmIDEOptions::CheckFlagTable(cmIDEFlagTable const* table, - const char* flag, bool& flag_handled) + std::string const& flag, bool& flag_handled) { + const char* pf = flag.c_str() + 1; // Look for an entry in the flag table matching this flag. for (cmIDEFlagTable const* entry = table; entry->IDEName; ++entry) { bool entry_found = false; @@ -102,17 +104,17 @@ bool cmIDEOptions::CheckFlagTable(cmIDEFlagTable const* table, // the entry specifies UserRequired we must match only if a // non-empty value is given. int n = static_cast<int>(strlen(entry->commandFlag)); - if ((strncmp(flag + 1, entry->commandFlag, n) == 0 || + if ((strncmp(pf, entry->commandFlag, n) == 0 || (entry->special & cmIDEFlagTable::CaseInsensitive && - cmsysString_strncasecmp(flag + 1, entry->commandFlag, n))) && + cmsysString_strncasecmp(pf, entry->commandFlag, n))) && (!(entry->special & cmIDEFlagTable::UserRequired) || - static_cast<int>(strlen(flag + 1)) > n)) { - this->FlagMapUpdate(entry, flag + n + 1); + static_cast<int>(strlen(pf)) > n)) { + this->FlagMapUpdate(entry, std::string(pf + n)); entry_found = true; } - } else if (strcmp(flag + 1, entry->commandFlag) == 0 || + } else if (strcmp(pf, entry->commandFlag) == 0 || (entry->special & cmIDEFlagTable::CaseInsensitive && - cmsysString_strcasecmp(flag + 1, entry->commandFlag) == 0)) { + cmsysString_strcasecmp(pf, entry->commandFlag) == 0)) { if (entry->special & cmIDEFlagTable::UserFollowing) { // This flag expects a value in the following argument. this->DoingFollowing = entry; @@ -137,7 +139,7 @@ bool cmIDEOptions::CheckFlagTable(cmIDEFlagTable const* table, } void cmIDEOptions::FlagMapUpdate(cmIDEFlagTable const* entry, - const char* new_value) + std::string const& new_value) { if (entry->special & cmIDEFlagTable::UserIgnored) { // Ignore the user-specified value. @@ -157,9 +159,9 @@ void cmIDEOptions::AddDefine(const std::string& def) this->Defines.push_back(def); } -void cmIDEOptions::AddDefines(const char* defines) +void cmIDEOptions::AddDefines(std::string const& defines) { - if (defines) { + if (!defines.empty()) { // Expand the list of definitions. cmSystemTools::ExpandListArgument(defines, this->Defines); } @@ -179,9 +181,9 @@ void cmIDEOptions::AddInclude(const std::string& include) this->Includes.push_back(include); } -void cmIDEOptions::AddIncludes(const char* includes) +void cmIDEOptions::AddIncludes(std::string const& includes) { - if (includes) { + if (!includes.empty()) { // Expand the list of includes. cmSystemTools::ExpandListArgument(includes, this->Includes); } diff --git a/Source/cmIDEOptions.h b/Source/cmIDEOptions.h index 54cb524..a4e5757 100644 --- a/Source/cmIDEOptions.h +++ b/Source/cmIDEOptions.h @@ -22,12 +22,12 @@ public: // Store definitions, includes and flags. void AddDefine(const std::string& define); - void AddDefines(const char* defines); + void AddDefines(std::string const& defines); void AddDefines(const std::vector<std::string>& defines); std::vector<std::string> const& GetDefines() const; void AddInclude(const std::string& includes); - void AddIncludes(const char* includes); + void AddIncludes(std::string const& includes); void AddIncludes(const std::vector<std::string>& includes); std::vector<std::string> const& GetIncludes() const; @@ -95,11 +95,12 @@ protected: FlagTableCount = 16 }; cmIDEFlagTable const* FlagTable[FlagTableCount]; - void HandleFlag(const char* flag); - bool CheckFlagTable(cmIDEFlagTable const* table, const char* flag, + void HandleFlag(std::string const& flag); + bool CheckFlagTable(cmIDEFlagTable const* table, std::string const& flag, bool& flag_handled); - void FlagMapUpdate(cmIDEFlagTable const* entry, const char* new_value); - virtual void StoreUnknownFlag(const char* flag) = 0; + void FlagMapUpdate(cmIDEFlagTable const* entry, + std::string const& new_value); + virtual void StoreUnknownFlag(std::string const& flag) = 0; }; #endif diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 394f976..b5291a1 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -5,6 +5,7 @@ #include "cmsys/Glob.hxx" #include <sstream> #include <stddef.h> +#include <string.h> #include <utility> #include "cmAlgorithms.h" @@ -334,8 +335,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // Check whether this is a DLL platform. bool dll_platform = - (this->Makefile->IsOn("WIN32") || this->Makefile->IsOn("CYGWIN") || - this->Makefile->IsOn("MINGW")); + strcmp(this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), + "") != 0; for (std::string const& tgt : targetList.GetVector()) { @@ -360,17 +361,6 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) this->SetError(e.str()); return false; } - if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { - std::string reason; - if (!this->Makefile->GetGlobalGenerator()->HasKnownObjectFileLocation( - &reason)) { - std::ostringstream e; - e << "TARGETS given OBJECT library \"" << tgt - << "\" which may not be installed" << reason << "."; - this->SetError(e.str()); - return false; - } - } // Store the target in the list to be installed. targets.push_back(target); } else { @@ -534,15 +524,23 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) case cmStateEnums::OBJECT_LIBRARY: { // Objects use OBJECT properties. if (!objectArgs.GetDestination().empty()) { + // Verify that we know where the objects are to install them. + std::string reason; + if (!this->Makefile->GetGlobalGenerator() + ->HasKnownObjectFileLocation(&reason)) { + std::ostringstream e; + e << "TARGETS given OBJECT library \"" << target.GetName() + << "\" whose objects may not be installed" << reason << "."; + this->SetError(e.str()); + return false; + } + objectGenerator = CreateInstallTargetGenerator(target, objectArgs, false); } else { - std::ostringstream e; - e << "TARGETS given no OBJECTS DESTINATION for object library " - "target \"" - << target.GetName() << "\"."; - this->SetError(e.str()); - return false; + // Installing an OBJECT library without a destination transforms + // it to an INTERFACE library. It installs no files but can be + // exported. } } break; case cmStateEnums::EXECUTABLE: { diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 8c889fc..c1af92f 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -10,6 +10,7 @@ #include <stdio.h> #include <utility> +#include "cmCryptoHash.h" #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" #include "cmGeneratedFileStream.h" @@ -24,6 +25,7 @@ #include "cmStateTypes.h" #include "cmSystemTools.h" #include "cmake.h" +#include "cmsys/FStream.hxx" cmLocalNinjaGenerator::cmLocalNinjaGenerator(cmGlobalGenerator* gg, cmMakefile* mf) @@ -286,8 +288,51 @@ void cmLocalNinjaGenerator::AppendCustomCommandDeps( } } +std::string cmLocalNinjaGenerator::WriteCommandScript( + std::vector<std::string> const& cmdLines, std::string const& customStep, + cmGeneratorTarget const* target) const +{ + std::string scriptPath; + if (target) { + scriptPath = target->GetSupportDirectory(); + } else { + scriptPath = this->GetCurrentBinaryDirectory(); + scriptPath += cmake::GetCMakeFilesDirectory(); + } + cmSystemTools::MakeDirectory(scriptPath); + scriptPath += '/'; + scriptPath += customStep; +#ifdef _WIN32 + scriptPath += ".bat"; +#else + scriptPath += ".sh"; +#endif + + cmsys::ofstream script(scriptPath.c_str()); + +#ifndef _WIN32 + script << "set -e\n\n"; +#endif + + for (auto const& i : cmdLines) { + std::string cmd = i; + // The command line was built assuming it would be written to + // the build.ninja file, so it uses '$$' for '$'. Remove this + // for the raw shell script. + cmSystemTools::ReplaceString(cmd, "$$", "$"); +#ifdef _WIN32 + script << cmd << " || exit /b" << '\n'; +#else + script << cmd << '\n'; +#endif + } + + return scriptPath; +} + std::string cmLocalNinjaGenerator::BuildCommandLine( - const std::vector<std::string>& cmdLines) + std::vector<std::string> const& cmdLines, std::string const& customStep, + cmGeneratorTarget const* target) const { // If we have no commands but we need to build a command anyway, use noop. // This happens when building a POST_BUILD value for link targets that @@ -296,6 +341,35 @@ std::string cmLocalNinjaGenerator::BuildCommandLine( return cmGlobalNinjaGenerator::SHELL_NOOP; } + // If this is a custom step then we will have no '$VAR' ninja placeholders. + // This means we can deal with long command sequences by writing to a script. + // Do this if the command lines are on the scale of the OS limit. + if (!customStep.empty()) { + size_t cmdLinesTotal = 0; + for (std::string const& cmd : cmdLines) { + cmdLinesTotal += cmd.length() + 6; + } + if (cmdLinesTotal > cmSystemTools::CalculateCommandLineLengthLimit() / 2) { + std::string const scriptPath = + this->WriteCommandScript(cmdLines, customStep, target); + std::string cmd +#ifndef _WIN32 + = "/bin/sh " +#endif + ; + cmd += this->ConvertToOutputFormat( + this->GetGlobalNinjaGenerator()->ConvertToNinjaPath(scriptPath), + cmOutputConverter::SHELL); + + // Add an unused argument based on script content so that Ninja + // knows when the command lines change. + cmd += " "; + cmCryptoHash hash(cmCryptoHash::AlgoSHA256); + cmd += hash.HashFile(scriptPath).substr(0, 16); + return cmd; + } + } + std::ostringstream cmd; for (std::vector<std::string>::const_iterator li = cmdLines.begin(); li != cmdLines.end(); ++li) @@ -406,10 +480,16 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( "Phony custom command for " + ninjaOutputs[0], ninjaOutputs, ninjaDeps, cmNinjaDeps(), orderOnlyDeps, cmNinjaVars()); } else { + std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]); + // Hash full path to make unique. + customStep += '-'; + cmCryptoHash hash(cmCryptoHash::AlgoSHA256); + customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7); + this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild( - this->BuildCommandLine(cmdLines), this->ConstructComment(ccg), - "Custom command for " + ninjaOutputs[0], cc->GetDepfile(), - cc->GetUsesTerminal(), + this->BuildCommandLine(cmdLines, customStep), + this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0], + cc->GetDepfile(), cc->GetUsesTerminal(), /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, ninjaDeps, orderOnlyDeps); } diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h index 95d8a61..f772fb0 100644 --- a/Source/cmLocalNinjaGenerator.h +++ b/Source/cmLocalNinjaGenerator.h @@ -59,7 +59,10 @@ public: return this->HomeRelativeOutputPath; } - std::string BuildCommandLine(const std::vector<std::string>& cmdLines); + std::string BuildCommandLine( + std::vector<std::string> const& cmdLines, + std::string const& customStep = std::string(), + cmGeneratorTarget const* target = nullptr) const; void AppendTargetOutputs(cmGeneratorTarget* target, cmNinjaDeps& outputs); void AppendTargetDepends( @@ -98,6 +101,10 @@ private: std::string MakeCustomLauncher(cmCustomCommandGenerator const& ccg); + std::string WriteCommandScript(std::vector<std::string> const& cmdLines, + std::string const& customStep, + cmGeneratorTarget const* target) const; + std::string HomeRelativeOutputPath; typedef std::map<cmCustomCommand const*, std::set<cmGeneratorTarget*>> diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index ddd8cc4..c9237a8 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -760,7 +760,8 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom( // Write special "cmake_check_build_system" target to run cmake with // the --check-build-system flag. - { + if (!this->GlobalGenerator->GlobalSettingIsOn( + "CMAKE_SUPPRESS_REGENERATION")) { // Build command to run CMake to check if anything needs regenerating. std::string cmakefileName = cmake::GetCMakeFilesDirectoryPostSlash(); cmakefileName += "Makefile.cmake"; @@ -1580,7 +1581,11 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( std::string recursiveTarget = this->GetCurrentBinaryDirectory(); recursiveTarget += "/all"; - depends.push_back("cmake_check_build_system"); + bool regenerate = + !this->GlobalGenerator->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION"); + if (regenerate) { + depends.push_back("cmake_check_build_system"); + } std::string progressDir = this->GetBinaryDirectory(); progressDir += cmake::GetCMakeFilesDirectory(); @@ -1643,7 +1648,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( if (!noall || cmSystemTools::IsOff(noall)) { // Drive the build before installing. depends.push_back("all"); - } else { + } else if (regenerate) { // At least make sure the build system is up to date. depends.push_back("cmake_check_build_system"); } @@ -1657,24 +1662,26 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( this->WriteMakeRule(ruleFileStream, "Prepare targets for installation.", "preinstall/fast", depends, commands, true); - // write the depend rule, really a recompute depends rule - depends.clear(); - commands.clear(); - std::string cmakefileName = cmake::GetCMakeFilesDirectoryPostSlash(); - cmakefileName += "Makefile.cmake"; - { - std::string runRule = - "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; - runRule += " --check-build-system "; - runRule += - this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); - runRule += " 1"; - commands.push_back(std::move(runRule)); + if (regenerate) { + // write the depend rule, really a recompute depends rule + depends.clear(); + commands.clear(); + std::string cmakefileName = cmake::GetCMakeFilesDirectoryPostSlash(); + cmakefileName += "Makefile.cmake"; + { + std::string runRule = + "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; + runRule += " --check-build-system "; + runRule += + this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); + runRule += " 1"; + commands.push_back(std::move(runRule)); + } + this->CreateCDCommand(commands, this->GetBinaryDirectory(), + this->GetCurrentBinaryDirectory()); + this->WriteMakeRule(ruleFileStream, "clear depends", "depend", depends, + commands, true); } - this->CreateCDCommand(commands, this->GetBinaryDirectory(), - this->GetCurrentBinaryDirectory()); - this->WriteMakeRule(ruleFileStream, "clear depends", "depend", depends, - commands, true); } void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf, diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 98b1c44..500a0aa 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -210,7 +210,8 @@ void cmLocalVisualStudio7Generator::CreateSingleVCProj( cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() { - if (this->Makefile->IsOn("CMAKE_SUPPRESS_REGENERATION")) { + if (this->GlobalGenerator->GlobalSettingIsOn( + "CMAKE_SUPPRESS_REGENERATION")) { return nullptr; } @@ -1677,8 +1678,8 @@ bool cmLocalVisualStudio7Generator::WriteGroup( } Options fileOptions(this, tool, table, gg->ExtraFlagTable); fileOptions.Parse(fc.CompileFlags.c_str()); - fileOptions.AddDefines(fc.CompileDefs.c_str()); - fileOptions.AddDefines(fc.CompileDefsConfig.c_str()); + fileOptions.AddDefines(fc.CompileDefs); + fileOptions.AddDefines(fc.CompileDefsConfig); // validate source level include directories std::vector<std::string> includes; this->AppendIncludeDirectories(includes, fc.IncludeDirs, **sf); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index b468208..1191490 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -6,12 +6,12 @@ #include "cmsys/RegularExpression.hxx" #include <algorithm> #include <assert.h> +#include <cstring> #include <ctype.h> #include <iterator> #include <memory> // IWYU pragma: keep #include <sstream> #include <stdlib.h> -#include <string.h> #include <utility> #include "cmAlgorithms.h" @@ -158,6 +158,26 @@ bool cmMakefile::CheckCMP0037(std::string const& targetName, return true; } +void cmMakefile::MaybeWarnCMP0074(std::string const& pkg) +{ + // Warn if a <pkg>_ROOT variable we may use is set. + std::string const varName = pkg + "_ROOT"; + bool const haveVar = this->GetDefinition(varName) != nullptr; + bool const haveEnv = cmSystemTools::HasEnv(varName); + if ((haveVar || haveEnv) && this->WarnedCMP0074.insert(varName).second) { + std::ostringstream w; + w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0074) << "\n"; + if (haveVar) { + w << "CMake variable " << varName << " is set.\n"; + } + if (haveEnv) { + w << "Environment variable " << varName << " is set.\n"; + } + w << "For compatibility, CMake is ignoring the variable."; + this->IssueMessage(cmake::AUTHOR_WARNING, w.str()); + } +} + cmStringRange cmMakefile::GetIncludeDirectoriesEntries() const { return this->StateSnapshot.GetDirectory().GetIncludeDirectoriesEntries(); @@ -1867,7 +1887,7 @@ cmTarget* cmMakefile::AddLibrary(const std::string& lname, // Clear its dependencies. Otherwise, dependencies might persist // over changes in CMakeLists.txt, making the information stale and // hence useless. - target->ClearDependencyInformation(*this, lname); + target->ClearDependencyInformation(*this); if (excludeFromAll) { target->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); } @@ -3138,6 +3158,14 @@ void cmMakefile::SetArgcArgv(const std::vector<std::string>& args) cmSourceFile* cmMakefile::GetSource(const std::string& sourceName, cmSourceFileLocationKind kind) const { + // First check "Known" paths (avoids the creation of cmSourceFileLocation) + if (kind == cmSourceFileLocationKind::Known) { + auto sfsi = this->KnownFileSearchIndex.find(sourceName); + if (sfsi != this->KnownFileSearchIndex.end()) { + return sfsi->second; + } + } + cmSourceFileLocation sfl(this, sourceName, kind); auto name = this->GetCMakeInstance()->StripExtension(sfl.GetName()); #if defined(_WIN32) || defined(__APPLE__) @@ -3170,6 +3198,10 @@ cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName, name = cmSystemTools::LowerCase(name); #endif this->SourceFileSearchIndex[name].push_back(sf); + // for "Known" paths add direct lookup (used for faster lookup in GetSource) + if (kind == cmSourceFileLocationKind::Known) { + this->KnownFileSearchIndex[sourceName] = sf; + } return sf; } @@ -3238,6 +3270,14 @@ int cmMakefile::TryCompile(const std::string& srcdir, // change to the tests directory and run cmake // use the cmake object instead of calling cmake cmWorkingDirectory workdir(bindir); + if (workdir.Failed()) { + this->IssueMessage(cmake::FATAL_ERROR, + "Failed to set working directory to " + bindir + " : " + + std::strerror(workdir.GetLastResult())); + cmSystemTools::SetFatalErrorOccured(); + this->IsSourceFileTryCompile = false; + return 1; + } // make sure the same generator is used // use this program as the cmake to be run, it should not @@ -3641,6 +3681,20 @@ void cmMakefile::AppendProperty(const std::string& prop, const char* value, const char* cmMakefile::GetProperty(const std::string& prop) const { + // Check for computed properties. + static std::string output; + if (prop == "TESTS") { + std::vector<std::string> keys; + // get list of keys + std::transform(this->Tests.begin(), this->Tests.end(), + std::back_inserter(keys), + [](decltype(this->Tests)::value_type const& pair) { + return pair.first; + }); + output = cmJoin(keys, ";"); + return output.c_str(); + } + return this->StateSnapshot.GetDirectory().GetProperty(prop); } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 5a30790..aafe60b 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -832,9 +832,11 @@ public: void RemoveExportBuildFileGeneratorCMP0024(cmExportBuildFileGenerator* gen); void AddExportBuildFileGenerator(cmExportBuildFileGenerator* gen); - // Maintain a stack of package names to determine the depth of find modules - // we are currently being called with - std::deque<std::string> FindPackageModuleStack; + // Maintain a stack of package roots to allow nested PACKAGE_ROOT_PATH + // searches + std::deque<std::vector<std::string>> FindPackageRootPathStack; + + void MaybeWarnCMP0074(std::string const& pkg); protected: // add link libraries and directories to the target @@ -861,6 +863,9 @@ protected: typedef std::unordered_map<std::string, SourceFileVec> SourceFileMap; SourceFileMap SourceFileSearchIndex; + // For "Known" paths we can store a direct filename to cmSourceFile map + std::unordered_map<std::string, cmSourceFile*> KnownFileSearchIndex; + // Tests std::map<std::string, cmTest*> Tests; @@ -998,6 +1003,7 @@ private: bool WarnUnused; bool CheckSystemVars; bool CheckCMP0000; + std::set<std::string> WarnedCMP0074; bool IsSourceFileTryCompile; mutable bool SuppressWatches; }; diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 73cf1f0..abe5ff3 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -643,6 +643,18 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( source.GetFullPath(), workingDirectory, compileCommand); } + // See if we need to use a compiler launcher like ccache or distcc + std::string compilerLauncher; + if (!compileCommands.empty() && (lang == "C" || lang == "CXX" || + lang == "Fortran" || lang == "CUDA")) { + std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; + const char* clauncher = + this->GeneratorTarget->GetProperty(clauncher_prop); + if (clauncher && *clauncher) { + compilerLauncher = clauncher; + } + } + // Maybe insert an include-what-you-use runner. if (!compileCommands.empty() && (lang == "C" || lang == "CXX")) { std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; @@ -656,6 +668,13 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( if ((iwyu && *iwyu) || (tidy && *tidy) || (cpplint && *cpplint) || (cppcheck && *cppcheck)) { std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_co_compile"; + if (!compilerLauncher.empty()) { + // In __run_co_compile case the launcher command is supplied + // via --launcher=<maybe-list> and consumed + run_iwyu += " --launcher="; + run_iwyu += this->LocalGenerator->EscapeForShell(compilerLauncher); + compilerLauncher.clear(); + } if (iwyu && *iwyu) { run_iwyu += " --iwyu="; run_iwyu += this->LocalGenerator->EscapeForShell(iwyu); @@ -682,21 +701,15 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } } - // Maybe insert a compiler launcher like ccache or distcc - if (!compileCommands.empty() && (lang == "C" || lang == "CXX" || - lang == "Fortran" || lang == "CUDA")) { - std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; - const char* clauncher = - this->GeneratorTarget->GetProperty(clauncher_prop); - if (clauncher && *clauncher) { - std::vector<std::string> launcher_cmd; - cmSystemTools::ExpandListArgument(clauncher, launcher_cmd, true); - for (std::string& i : launcher_cmd) { - i = this->LocalGenerator->EscapeForShell(i); - } - std::string const& run_launcher = cmJoin(launcher_cmd, " ") + " "; - compileCommands.front().insert(0, run_launcher); + // If compiler launcher was specified and not consumed above, it + // goes to the beginning of the command line. + if (!compileCommands.empty() && !compilerLauncher.empty()) { + std::vector<std::string> args; + cmSystemTools::ExpandListArgument(compilerLauncher, args, true); + for (std::string& i : args) { + i = this->LocalGenerator->EscapeForShell(i); } + compileCommands.front().insert(0, cmJoin(args, " ") + " "); } std::string launcher; diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index ddbc772..f1fb2d2 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -976,8 +976,10 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() preLinkCmdLines.push_back("cd " + homeOutDir); } - vars["PRE_LINK"] = localGen.BuildCommandLine(preLinkCmdLines); - std::string postBuildCmdLine = localGen.BuildCommandLine(postBuildCmdLines); + vars["PRE_LINK"] = localGen.BuildCommandLine(preLinkCmdLines, "pre-link", + this->GeneratorTarget); + std::string postBuildCmdLine = localGen.BuildCommandLine( + postBuildCmdLines, "post-build", this->GeneratorTarget); cmNinjaVars symlinkVars; bool const symlinkNeeded = diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index f4faf47..fa7d95a 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -653,6 +653,17 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) cmSystemTools::ExpandListArgument(compileCmd, compileCmds); } + // See if we need to use a compiler launcher like ccache or distcc + std::string compilerLauncher; + if (!compileCmds.empty() && + (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA")) { + std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; + const char* clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); + if (clauncher && *clauncher) { + compilerLauncher = clauncher; + } + } + // Maybe insert an include-what-you-use runner. if (!compileCmds.empty() && (lang == "C" || lang == "CXX")) { std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; @@ -668,6 +679,13 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) std::string run_iwyu = this->GetLocalGenerator()->ConvertToOutputFormat( cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL); run_iwyu += " -E __run_co_compile"; + if (!compilerLauncher.empty()) { + // In __run_co_compile case the launcher command is supplied + // via --launcher=<maybe-list> and consumed + run_iwyu += " --launcher="; + run_iwyu += this->LocalGenerator->EscapeForShell(compilerLauncher); + compilerLauncher.clear(); + } if (iwyu && *iwyu) { run_iwyu += " --iwyu="; run_iwyu += this->GetLocalGenerator()->EscapeForShell(iwyu); @@ -693,20 +711,15 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) } } - // Maybe insert a compiler launcher like ccache or distcc - if (!compileCmds.empty() && - (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA")) { - std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; - const char* clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); - if (clauncher && *clauncher) { - std::vector<std::string> launcher_cmd; - cmSystemTools::ExpandListArgument(clauncher, launcher_cmd, true); - for (std::string& i : launcher_cmd) { - i = this->LocalGenerator->EscapeForShell(i); - } - std::string const& run_launcher = cmJoin(launcher_cmd, " ") + " "; - compileCmds.front().insert(0, run_launcher); + // If compiler launcher was specified and not consumed above, it + // goes to the beginning of the command line. + if (!compileCmds.empty() && !compilerLauncher.empty()) { + std::vector<std::string> args; + cmSystemTools::ExpandListArgument(compilerLauncher, args, true); + for (std::string& i : args) { + i = this->LocalGenerator->EscapeForShell(i); } + compileCmds.front().insert(0, cmJoin(args, " ") + " "); } if (!compileCmds.empty()) { @@ -856,9 +869,27 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( vars["FLAGS"] = this->ComputeFlagsForObject(source, language); vars["DEFINES"] = this->ComputeDefines(source, language); vars["INCLUDES"] = this->ComputeIncludes(source, language); + if (!this->NeedDepTypeMSVC(language)) { - vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat( - objectFileName + ".d", cmOutputConverter::SHELL); + bool replaceExt(false); + if (!language.empty()) { + std::string repVar = "CMAKE_"; + repVar += language; + repVar += "_DEPFILE_EXTENSION_REPLACE"; + replaceExt = this->Makefile->IsOn(repVar); + } + if (!replaceExt) { + // use original code + vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat( + objectFileName + ".d", cmOutputConverter::SHELL); + } else { + // Replace the original source file extension with the + // depend file extension. + std::string dependFileName = + cmSystemTools::GetFilenameWithoutLastExtension(objectFileName) + ".d"; + vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat( + objectFileDir + "/" + dependFileName, cmOutputConverter::SHELL); + } } this->ExportObjectCompileCommand( diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx index 7adeb8e..cc6d4b9 100644 --- a/Source/cmNinjaUtilityTargetGenerator.cxx +++ b/Source/cmNinjaUtilityTargetGenerator.cxx @@ -96,8 +96,8 @@ void cmNinjaUtilityTargetGenerator::Generate() this->GetBuildFileStream(), "Utility command for " + this->GetTargetName(), outputs, deps); } else { - std::string command = - this->GetLocalGenerator()->BuildCommandLine(commands); + std::string command = this->GetLocalGenerator()->BuildCommandLine( + commands, "utility", this->GeneratorTarget); const char* echoStr = this->GetGeneratorTarget()->GetProperty("EchoString"); std::string desc; diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 25db929..fd42c53 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -6,7 +6,7 @@ #include <assert.h> #include <ctype.h> #include <set> -#include <sstream> +#include <string.h> #include <vector> #include "cmAlgorithms.h" @@ -341,12 +341,13 @@ redirection character (for example, ^>, ^<, or ^| ). If you need to use the caret character itself (^), use two in a row (^^). */ -int cmOutputConverter::Shell__CharIsWhitespace(char c) +/* Some helpers to identify character classes */ +static int Shell__CharIsWhitespace(char c) { return ((c == ' ') || (c == '\t')); } -int cmOutputConverter::Shell__CharNeedsQuotesOnUnix(char c) +static int Shell__CharNeedsQuotesOnUnix(char c) { return ((c == '\'') || (c == '`') || (c == ';') || (c == '#') || (c == '&') || (c == '$') || (c == '(') || (c == ')') || (c == '~') || @@ -354,12 +355,17 @@ int cmOutputConverter::Shell__CharNeedsQuotesOnUnix(char c) (c == '\\')); } -int cmOutputConverter::Shell__CharNeedsQuotesOnWindows(char c) +static int Shell__CharNeedsQuotesOnWindows(char c) { return ((c == '\'') || (c == '#') || (c == '&') || (c == '<') || (c == '>') || (c == '|') || (c == '^')); } +static int Shell__CharIsMakeVariableName(char c) +{ + return c && (c == '_' || isalpha((static_cast<int>(c)))); +} + int cmOutputConverter::Shell__CharNeedsQuotes(char c, int flags) { /* On Windows the built-in command shell echo never needs quotes. */ @@ -386,11 +392,6 @@ int cmOutputConverter::Shell__CharNeedsQuotes(char c, int flags) return 0; } -int cmOutputConverter::Shell__CharIsMakeVariableName(char c) -{ - return c && (c == '_' || isalpha((static_cast<int>(c)))); -} - const char* cmOutputConverter::Shell__SkipMakeVariables(const char* c) { while (*c == '$' && *(c + 1) == '(') { @@ -481,7 +482,9 @@ int cmOutputConverter::Shell__ArgumentNeedsQuotes(const char* in, int flags) std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) { - std::ostringstream out; + /* Output will be at least as long as input string. */ + std::string out; + out.reserve(strlen(in)); /* String iterator. */ const char* c; @@ -495,11 +498,11 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) /* Add the opening quote for this argument. */ if (flags & Shell_Flag_WatcomQuote) { if (flags & Shell_Flag_IsUnix) { - out << '"'; + out += '"'; } - out << '\''; + out += '\''; } else { - out << '"'; + out += '"'; } } @@ -511,7 +514,7 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) if (skip != c) { /* Copy to the end of the make variable references. */ while (c != skip) { - out << *c++; + out += *c++; } /* The make variable reference eliminates any escaping needed @@ -531,7 +534,7 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) quoted argument. */ if (*c == '\\' || *c == '"' || *c == '`' || *c == '$') { /* This character needs a backslash to escape it. */ - out << '\\'; + out += '\\'; } } else if (flags & Shell_Flag_EchoWindows) { /* On Windows the built-in command shell echo never needs escaping. */ @@ -545,11 +548,11 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) backslashes. */ while (windows_backslashes > 0) { --windows_backslashes; - out << '\\'; + out += '\\'; } /* Add the backslash to escape the double-quote. */ - out << '\\'; + out += '\\'; } else { /* We encountered a normal character. This eliminates any escaping needed for preceding backslashes. */ @@ -562,7 +565,7 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) if (flags & Shell_Flag_Make) { /* In Makefiles a dollar is written $$. The make tool will replace it with just $ before passing it to the shell. */ - out << "$$"; + out += "$$"; } else if (flags & Shell_Flag_VSIDE) { /* In a VS IDE a dollar is written "$". If this is written in an un-quoted argument it starts a quoted segment, inserts @@ -570,30 +573,30 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) argument it ends quoting, inserts the $ and restarts quoting. Either way the $ is isolated from surrounding text to avoid looking like a variable reference. */ - out << "\"$\""; + out += "\"$\""; } else { /* Otherwise a dollar is written just $. */ - out << '$'; + out += '$'; } } else if (*c == '#') { if ((flags & Shell_Flag_Make) && (flags & Shell_Flag_WatcomWMake)) { /* In Watcom WMake makefiles a pound is written $#. The make tool will replace it with just # before passing it to the shell. */ - out << "$#"; + out += "$#"; } else { /* Otherwise a pound is written just #. */ - out << '#'; + out += '#'; } } else if (*c == '%') { if ((flags & Shell_Flag_VSIDE) || ((flags & Shell_Flag_Make) && ((flags & Shell_Flag_MinGWMake) || (flags & Shell_Flag_NMake)))) { /* In the VS IDE, NMake, or MinGW make a percent is written %%. */ - out << "%%"; + out += "%%"; } else { /* Otherwise a percent is written just %. */ - out << '%'; + out += '%'; } } else if (*c == ';') { if (flags & Shell_Flag_VSIDE) { @@ -602,14 +605,14 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) inserts the ; and ends the segment. If it is written in a quoted argument it ends quoting, inserts the ; and restarts quoting. Either way the ; is isolated. */ - out << "\";\""; + out += "\";\""; } else { /* Otherwise a semicolon is written just ;. */ - out << ';'; + out += ';'; } } else { /* Store this character. */ - out << *c; + out += *c; } } @@ -617,19 +620,19 @@ std::string cmOutputConverter::Shell__GetArgument(const char* in, int flags) /* Add enough backslashes to escape any trailing ones. */ while (windows_backslashes > 0) { --windows_backslashes; - out << '\\'; + out += '\\'; } /* Add the closing quote for this argument. */ if (flags & Shell_Flag_WatcomQuote) { - out << '\''; + out += '\''; if (flags & Shell_Flag_IsUnix) { - out << '"'; + out += '"'; } } else { - out << '"'; + out += '"'; } } - return out.str(); + return out; } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index ae15055..ed7143c 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -117,11 +117,7 @@ public: private: cmState* GetState() const; - static int Shell__CharIsWhitespace(char c); - static int Shell__CharNeedsQuotesOnUnix(char c); - static int Shell__CharNeedsQuotesOnWindows(char c); static int Shell__CharNeedsQuotes(char c, int flags); - static int Shell__CharIsMakeVariableName(char c); static const char* Shell__SkipMakeVariables(const char* c); static int Shell__ArgumentNeedsQuotes(const char* in, int flags); static std::string Shell__GetArgument(const char* in, int flags); diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index c39f927..34fe09d 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -214,7 +214,12 @@ class cmMakefile; 3, 10, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0072, \ "FindOpenGL prefers GLVND by default when available.", 3, 11, 0, \ - cmPolicies::WARN) + cmPolicies::WARN) \ + SELECT(POLICY, CMP0073, \ + "Do not produce legacy _LIB_DEPENDS cache entries.", 3, 12, 0, \ + cmPolicies::WARN) \ + SELECT(POLICY, CMP0074, "find_package uses PackageName_ROOT variables.", 3, \ + 12, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ @@ -238,7 +243,8 @@ class cmMakefile; F(CMP0063) \ F(CMP0065) \ F(CMP0068) \ - F(CMP0069) + F(CMP0069) \ + F(CMP0073) /** \class cmPolicies * \brief Handles changes in CMake behavior and policies diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx index dfa1858..6ddb0b8 100644 --- a/Source/cmProjectCommand.cxx +++ b/Source/cmProjectCommand.cxx @@ -3,9 +3,11 @@ #include "cmProjectCommand.h" #include "cmsys/RegularExpression.hxx" +#include <functional> #include <sstream> #include <stdio.h> +#include "cmAlgorithms.h" #include "cmMakefile.h" #include "cmPolicies.h" #include "cmStateTypes.h" @@ -66,12 +68,19 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args, bool haveVersion = false; bool haveLanguages = false; bool haveDescription = false; + bool haveHomepage = false; std::string version; std::string description; + std::string homepage; std::vector<std::string> languages; + std::function<void()> missedValueReporter; + auto resetReporter = [&missedValueReporter]() { + missedValueReporter = std::function<void()>(); + }; enum Doing { DoingDescription, + DoingHomepage, DoingLanguages, DoingVersion }; @@ -85,7 +94,18 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args, return true; } haveLanguages = true; + if (missedValueReporter) { + missedValueReporter(); + } doing = DoingLanguages; + if (!languages.empty()) { + std::string msg = + "the following parameters must be specified after LANGUAGES " + "keyword: "; + msg += cmJoin(languages, ", "); + msg += '.'; + this->Makefile->IssueMessage(cmake::WARNING, msg); + } } else if (args[i] == "VERSION") { if (haveVersion) { this->Makefile->IssueMessage(cmake::FATAL_ERROR, @@ -94,7 +114,17 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args, return true; } haveVersion = true; + if (missedValueReporter) { + missedValueReporter(); + } doing = DoingVersion; + missedValueReporter = [this, &resetReporter]() { + this->Makefile->IssueMessage( + cmake::WARNING, + "VERSION keyword not followed by a value or was followed by a " + "value that expanded to nothing."); + resetReporter(); + }; } else if (args[i] == "DESCRIPTION") { if (haveDescription) { this->Makefile->IssueMessage( @@ -103,23 +133,61 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args, return true; } haveDescription = true; + if (missedValueReporter) { + missedValueReporter(); + } doing = DoingDescription; + missedValueReporter = [this, &resetReporter]() { + this->Makefile->IssueMessage( + cmake::WARNING, + "DESCRIPTION keyword not followed by a value or was followed " + "by a value that expanded to nothing."); + resetReporter(); + }; + } else if (args[i] == "HOMEPAGE_URL") { + if (haveHomepage) { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, "HOMEPAGE_URL may be specified at most once."); + cmSystemTools::SetFatalErrorOccured(); + return true; + } + haveHomepage = true; + doing = DoingHomepage; + missedValueReporter = [this, &resetReporter]() { + this->Makefile->IssueMessage( + cmake::WARNING, + "HOMEPAGE_URL keyword not followed by a value or was followed " + "by a value that expanded to nothing."); + resetReporter(); + }; } else if (doing == DoingVersion) { doing = DoingLanguages; version = args[i]; + resetReporter(); } else if (doing == DoingDescription) { doing = DoingLanguages; description = args[i]; + resetReporter(); + } else if (doing == DoingHomepage) { + doing = DoingLanguages; + homepage = args[i]; + resetReporter(); } else // doing == DoingLanguages { languages.push_back(args[i]); } } - if (haveVersion && !haveLanguages && !languages.empty()) { + if (missedValueReporter) { + missedValueReporter(); + } + + if ((haveVersion || haveDescription || haveHomepage) && !haveLanguages && + !languages.empty()) { this->Makefile->IssueMessage( cmake::FATAL_ERROR, - "project with VERSION must use LANGUAGES before language names."); + "project with VERSION, DESCRIPTION or HOMEPAGE_URL must " + "use LANGUAGES before language names."); cmSystemTools::SetFatalErrorOccured(); return true; } @@ -216,6 +284,8 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args, if (haveDescription) { this->Makefile->AddDefinition("PROJECT_DESCRIPTION", description.c_str()); + this->Makefile->AddDefinition(projectName + "_DESCRIPTION", + description.c_str()); // Set the CMAKE_PROJECT_DESCRIPTION variable to be the highest-level // project name in the tree. If there are two project commands // in the same CMakeLists.txt file, and it is the top level @@ -230,6 +300,24 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args, } } + if (haveHomepage) { + this->Makefile->AddDefinition("PROJECT_HOMEPAGE_URL", homepage.c_str()); + this->Makefile->AddDefinition(projectName + "_HOMEPAGE_URL", + homepage.c_str()); + // Set the CMAKE_PROJECT_HOMEPAGE_URL variable to be the highest-level + // project name in the tree. If there are two project commands + // in the same CMakeLists.txt file, and it is the top level + // CMakeLists.txt file, then go with the last one. + if (!this->Makefile->GetDefinition("CMAKE_PROJECT_HOMEPAGE_URL") || + (this->Makefile->IsRootMakefile())) { + this->Makefile->AddDefinition("CMAKE_PROJECT_HOMEPAGE_URL", + homepage.c_str()); + this->Makefile->AddCacheDefinition( + "CMAKE_PROJECT_HOMEPAGE_URL", homepage.c_str(), + "Value Computed by CMake", cmStateEnums::STATIC); + } + } + if (languages.empty()) { // if no language is specified do c and c++ languages.push_back("C"); diff --git a/Source/cmQtAutoGeneratorMocUic.cxx b/Source/cmQtAutoGeneratorMocUic.cxx index 6be65ee..37cf0f8 100644 --- a/Source/cmQtAutoGeneratorMocUic.cxx +++ b/Source/cmQtAutoGeneratorMocUic.cxx @@ -434,7 +434,7 @@ bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocSource(WorkerT& wrk, JobHandleT jobHandle(new JobMocT(std::move(jobPre.SourceFile), FileName, std::move(jobPre.IncludeString))); if (jobPre.self) { - // Read depdendencies from this source + // Read dependencies from this source static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content); } if (!wrk.Gen().ParallelJobPushMoc(jobHandle)) { @@ -452,7 +452,7 @@ bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocHeader(WorkerT& wrk, if (!macroName.empty()) { JobHandleT jobHandle( new JobMocT(std::string(FileName), std::string(), std::string())); - // Read depdendencies from this source + // Read dependencies from this source static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content); success = wrk.Gen().ParallelJobPushMoc(jobHandle); } @@ -1373,7 +1373,7 @@ bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile) // Compare list sizes if (sources.size() != options.size()) { std::ostringstream ost; - ost << "files/options lists sizes missmatch (" << sources.size() << "/" + ost << "files/options lists sizes mismatch (" << sources.size() << "/" << options.size() << ")"; Log().ErrorFile(GeneratorT::UIC, InfoFile(), ost.str()); return false; diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h index 7b19210..a7d8cee 100644 --- a/Source/cmRulePlaceholderExpander.h +++ b/Source/cmRulePlaceholderExpander.h @@ -24,7 +24,7 @@ public: this->TargetImpLib = targetImpLib; } - // Create a struct to hold the varibles passed into + // Create a struct to hold the variables passed into // ExpandRuleVariables struct RuleVariables { diff --git a/Source/cmSearchPath.h b/Source/cmSearchPath.h index fd0c7c5..2a576ed 100644 --- a/Source/cmSearchPath.h +++ b/Source/cmSearchPath.h @@ -39,10 +39,10 @@ public: void AddCMakePrefixPath(const std::string& variable); void AddEnvPrefixPath(const std::string& variable, bool stripBin = false); void AddSuffixes(const std::vector<std::string>& suffixes); - -protected: void AddPrefixPaths(const std::vector<std::string>& paths, const char* base = nullptr); + +protected: void AddPathInternal(const std::string& path, const char* base = nullptr); cmFindCommon* FC; diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index 55af078..9631912 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -68,6 +68,9 @@ bool cmStringCommand::InitialPass(std::vector<std::string> const& args, if (subCommand == "CONCAT") { return this->HandleConcatCommand(args); } + if (subCommand == "JOIN") { + return this->HandleJoinCommand(args); + } if (subCommand == "SUBSTRING") { return this->HandleSubstringCommand(args); } @@ -677,8 +680,26 @@ bool cmStringCommand::HandleConcatCommand(std::vector<std::string> const& args) return false; } - std::string const& variableName = args[1]; - std::string value = cmJoin(cmMakeRange(args).advance(2), std::string()); + return this->joinImpl(args, std::string(), 1); +} + +bool cmStringCommand::HandleJoinCommand(std::vector<std::string> const& args) +{ + if (args.size() < 3) { + this->SetError("sub-command JOIN requires at least two arguments."); + return false; + } + + return this->joinImpl(args, args[1], 2); +} + +bool cmStringCommand::joinImpl(std::vector<std::string> const& args, + std::string const& glue, const size_t varIdx) +{ + std::string const& variableName = args[varIdx]; + // NOTE Items to concat/join placed right after the variable for + // both `CONCAT` and `JOIN` sub-commands. + std::string value = cmJoin(cmMakeRange(args).advance(varIdx + 1), glue); this->Makefile->AddDefinition(variableName, value.c_str()); return true; diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h index b287e37..569ed83 100644 --- a/Source/cmStringCommand.h +++ b/Source/cmStringCommand.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstddef> #include <string> #include <vector> @@ -48,6 +49,7 @@ protected: bool HandleAppendCommand(std::vector<std::string> const& args); bool HandlePrependCommand(std::vector<std::string> const& args); bool HandleConcatCommand(std::vector<std::string> const& args); + bool HandleJoinCommand(std::vector<std::string> const& args); bool HandleStripCommand(std::vector<std::string> const& args); bool HandleRandomCommand(std::vector<std::string> const& args); bool HandleFindCommand(std::vector<std::string> const& args); @@ -56,6 +58,9 @@ protected: bool HandleGenexStripCommand(std::vector<std::string> const& args); bool HandleUuidCommand(std::vector<std::string> const& args); + bool joinImpl(std::vector<std::string> const& args, std::string const& glue, + size_t varIdx); + class RegexReplacement { public: diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index cd11c4b..6137223 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -114,15 +114,12 @@ const char* cmTargetPropertyComputer::GetSources<cmTarget>( } if (!noMessage) { e << "Target \"" << tgt->GetName() - << "\" contains " - "$<TARGET_OBJECTS> generator expression in its sources " - "list. " - "This content was not previously part of the SOURCES " - "property " - "when that property was read at configure time. Code " - "reading " - "that property needs to be adapted to ignore the generator " - "expression using the string(GENEX_STRIP) command."; + << "\" contains $<TARGET_OBJECTS> generator expression in its " + "sources list. This content was not previously part of the " + "SOURCES property when that property was read at configure " + "time. Code reading that property needs to be adapted to " + "ignore the generator expression using the string(GENEX_STRIP) " + "command."; messenger->IssueMessage(messageType, e.str(), context); } if (addContent) { @@ -189,18 +186,10 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->ImportedGloballyVisible = vis == VisibilityImportedGlobally; this->BuildInterfaceIncludesAppended = false; - // only add dependency information for library targets - if (this->TargetTypeValue >= cmStateEnums::STATIC_LIBRARY && - this->TargetTypeValue <= cmStateEnums::MODULE_LIBRARY) { - this->RecordDependencies = true; - } else { - this->RecordDependencies = false; - } - // Check whether this is a DLL platform. this->DLLPlatform = - (this->Makefile->IsOn("WIN32") || this->Makefile->IsOn("CYGWIN") || - this->Makefile->IsOn("MINGW")); + strcmp(this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), + "") != 0; // Check whether we are targeting an Android platform. this->IsAndroid = @@ -509,7 +498,7 @@ std::string cmTarget::ProcessSourceItemCMP0049(const std::string& s) { std::string src = s; - // For backwards compatibility replace varibles in source names. + // For backwards compatibility replace variables in source names. // This should eventually be removed. this->Makefile->ExpandVariablesInString(src); if (src != s) { @@ -638,27 +627,11 @@ const std::vector<std::string>& cmTarget::GetLinkDirectories() const return this->LinkDirectories; } -void cmTarget::ClearDependencyInformation(cmMakefile& mf, - const std::string& target) +void cmTarget::ClearDependencyInformation(cmMakefile& mf) { - // Clear the dependencies. The cache variable must exist iff we are - // recording dependency information for this target. - std::string depname = target; + std::string depname = this->GetName(); depname += "_LIB_DEPENDS"; - if (this->RecordDependencies) { - mf.AddCacheDefinition(depname, "", "Dependencies for target", - cmStateEnums::STATIC); - } else { - if (mf.GetDefinition(depname)) { - std::string message = "Target "; - message += target; - message += " has dependency information when it shouldn't.\n"; - message += "Your cache is probably stale. Please remove the entry\n "; - message += depname; - message += "\nfrom the cache."; - cmSystemTools::Error(message.c_str()); - } - } + mf.RemoveCacheDefinition(depname); } std::string cmTarget::GetDebugGeneratorExpressions( @@ -742,7 +715,8 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib, } if (cmGeneratorExpression::Find(lib) != std::string::npos || - (tgt && tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) || + (tgt && (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY || + tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) || (this->Name == lib)) { return; } @@ -754,7 +728,7 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib, this->OriginalLinkLibraries.emplace_back(lib, llt); } - // Add the explicit dependency information for this target. This is + // Add the explicit dependency information for libraries. This is // simply a set of libraries separated by ";". There should always // be a trailing ";". These library names are not canonical, in that // they may be "-framework x", "-ly", "/path/libz.a", etc. @@ -762,7 +736,10 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib, // may be purposefully duplicated to handle recursive dependencies, // and we removing one instance will break the link line. Duplicates // will be appropriately eliminated at emit time. - if (this->RecordDependencies) { + if (this->TargetTypeValue >= cmStateEnums::STATIC_LIBRARY && + this->TargetTypeValue <= cmStateEnums::MODULE_LIBRARY && + (this->GetPolicyStatusCMP0073() == cmPolicies::OLD || + this->GetPolicyStatusCMP0073() == cmPolicies::WARN)) { std::string targetEntry = this->Name; targetEntry += "_LIB_DEPENDS"; std::string dependencies; diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 56f3e3a..62c4e22 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -137,7 +137,7 @@ public: /** * Clear the dependency information recorded for this target, if any. */ - void ClearDependencyInformation(cmMakefile& mf, const std::string& target); + void ClearDependencyInformation(cmMakefile& mf); void AddLinkLibrary(cmMakefile& mf, const std::string& lib, cmTargetLinkLibraryType llt); @@ -310,7 +310,6 @@ private: cmTargetInternalPointer Internal; cmStateEnums::TargetType TargetTypeValue; bool HaveInstallRule; - bool RecordDependencies; bool DLLPlatform; bool IsAndroid; bool IsImportedTarget; diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index 9e4575a..699fff8 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -94,16 +94,6 @@ bool cmTargetLinkLibrariesCommand::InitialPass( return true; } - // OBJECT libraries are not allowed on the LHS of the command. - if (this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { - std::ostringstream e; - e << "Object library target \"" << args[0] << "\" " - << "may not link to anything."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); - cmSystemTools::SetFatalErrorOccured(); - return true; - } - // Having a UTILITY library on the LHS is a bug. if (this->Target->GetType() == cmStateEnums::UTILITY) { std::ostringstream e; @@ -401,14 +391,15 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib, if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) && (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) && (tgt->GetType() != cmStateEnums::UNKNOWN_LIBRARY) && + (tgt->GetType() != cmStateEnums::OBJECT_LIBRARY) && (tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) && !tgt->IsExecutableWithExports()) { std::ostringstream e; e << "Target \"" << lib << "\" of type " << cmState::GetTargetTypeName(tgt->GetType()) << " may not be linked into another target. One may link only to " - "INTERFACE, STATIC or SHARED libraries, or to executables with the " - "ENABLE_EXPORTS property set."; + "INTERFACE, OBJECT, STATIC or SHARED libraries, or to executables " + "with the ENABLE_EXPORTS property set."; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index ec31bd6..87d3c78 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -18,6 +18,58 @@ #include <iterator> #include <memory> // IWYU pragma: keep +struct cmVisualStudio10TargetGenerator::Elem +{ + cmGeneratedFileStream& S; + int Indent; + bool HasElements = false; + + Elem(cmGeneratedFileStream& s, int i) + : S(s) + , Indent(i) + { + } + Elem(Elem& par) + : S(par.S) + , Indent(par.Indent + 1) + { + par.SetHasElements(); + } + void SetHasElements() + { + if (!HasElements) { + S << ">\n"; + HasElements = true; + } + } + void WriteEndTag(const char* tag) + { + if (HasElements) { + S.fill(' '); + S.width(Indent * 2); + S << "</" << tag << ">\n"; + } else { + S << " />\n"; + } + } +}; + +inline void cmVisualStudio10TargetGenerator::WriteElem(const char* tag, + const char* val, + int indentLevel) +{ + this->WriteString("<", indentLevel); + (*this->BuildFileStream) << tag << ">" << val << "</" << tag << ">\n"; +} + +inline void cmVisualStudio10TargetGenerator::WriteElem(const char* tag, + std::string const& val, + int indentLevel) +{ + this->WriteString("<", indentLevel); + (*this->BuildFileStream) << tag << ">" << val << "</" << tag << ">\n"; +} + static void ConvertToWindowsSlash(std::string& s); static std::string cmVS10EscapeXML(std::string arg) @@ -28,6 +80,12 @@ static std::string cmVS10EscapeXML(std::string arg) return arg; } +inline void cmVisualStudio10TargetGenerator::WriteElemEscapeXML( + const char* tag, std::string const& val, int indentLevel) +{ + this->WriteElem(tag, cmVS10EscapeXML(val), indentLevel); +} + static std::string cmVS10EscapeQuotes(std::string arg) { cmSystemTools::ReplaceString(arg, "\"", """); @@ -84,16 +142,15 @@ static std::string computeProjectFileExtension(cmGeneratorTarget const* t, cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator( cmGeneratorTarget* target, cmGlobalVisualStudio10Generator* gg) + : GeneratorTarget(target) + , Makefile(target->Target->GetMakefile()) + , Platform(gg->GetPlatformName()) + , Name(target->GetName()) + , GUID(gg->GetGUID(this->Name)) + , GlobalGenerator(gg) + , LocalGenerator((cmLocalVisualStudio7Generator*)target->GetLocalGenerator()) { - this->GlobalGenerator = gg; - this->GeneratorTarget = target; - this->Makefile = target->Target->GetMakefile(); this->Makefile->GetConfigurations(this->Configurations); - this->LocalGenerator = - (cmLocalVisualStudio7Generator*)this->GeneratorTarget->GetLocalGenerator(); - this->Name = this->GeneratorTarget->GetName(); - this->GUID = this->GlobalGenerator->GetGUID(this->Name); - this->Platform = gg->GetPlatformName(); this->NsightTegra = gg->IsNsightTegra(); for (int i = 0; i < 4; ++i) { this->NsightTegraVersion[i] = 0; @@ -266,16 +323,10 @@ void cmVisualStudio10TargetGenerator::Generate() } (*this->BuildFileStream) << "</NsightTegraProjectRevisionNumber>\n"; // Tell newer versions to upgrade silently when loading. - this->WriteString("<NsightTegraUpgradeOnceWithoutPrompt>" - "true" - "</NsightTegraUpgradeOnceWithoutPrompt>\n", - 2); + this->WriteElem("NsightTegraUpgradeOnceWithoutPrompt", "true", 2); } else { // Require Nsight Tegra 1.6 for JCompile support. - this->WriteString("<NsightTegraProjectRevisionNumber>" - "7" - "</NsightTegraProjectRevisionNumber>\n", - 2); + this->WriteElem("NsightTegraProjectRevisionNumber", "7", 2); } this->WriteString("</PropertyGroup>\n", 1); } @@ -283,9 +334,7 @@ void cmVisualStudio10TargetGenerator::Generate() if (const char* hostArch = this->GlobalGenerator->GetPlatformToolsetHostArchitecture()) { this->WriteString("<PropertyGroup>\n", 1); - this->WriteString("<PreferredToolArchitecture>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(hostArch) - << "</PreferredToolArchitecture>\n"; + this->WriteElemEscapeXML("PreferredToolArchitecture", hostArch, 2); this->WriteString("</PropertyGroup>\n", 1); } @@ -293,8 +342,7 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteProjectConfigurations(); } this->WriteString("<PropertyGroup Label=\"Globals\">\n", 1); - this->WriteString("<ProjectGuid>", 2); - (*this->BuildFileStream) << "{" << this->GUID << "}</ProjectGuid>\n"; + this->WriteElem("ProjectGuid", "{" + this->GUID + "}", 2); if (this->MSTools && this->GeneratorTarget->GetType() <= cmStateEnums::GLOBAL_TARGET) { @@ -323,61 +371,45 @@ void cmVisualStudio10TargetGenerator::Generate() this->GeneratorTarget->GetProperty("VS_SCC_PROVIDER"); if (vsProjectName && vsLocalPath && vsProvider) { - this->WriteString("<SccProjectName>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(vsProjectName) - << "</SccProjectName>\n"; - this->WriteString("<SccLocalPath>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(vsLocalPath) - << "</SccLocalPath>\n"; - this->WriteString("<SccProvider>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(vsProvider) - << "</SccProvider>\n"; + this->WriteElemEscapeXML("SccProjectName", vsProjectName, 2); + this->WriteElemEscapeXML("SccLocalPath", vsLocalPath, 2); + this->WriteElemEscapeXML("SccProvider", vsProvider, 2); const char* vsAuxPath = this->GeneratorTarget->GetProperty("VS_SCC_AUXPATH"); if (vsAuxPath) { - this->WriteString("<SccAuxPath>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(vsAuxPath) - << "</SccAuxPath>\n"; + this->WriteElemEscapeXML("SccAuxPath", vsAuxPath, 2); } } if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT")) { - this->WriteString("<WinMDAssembly>true</WinMDAssembly>\n", 2); + this->WriteElem("WinMDAssembly", "true", 2); } const char* vsGlobalKeyword = this->GeneratorTarget->GetProperty("VS_GLOBAL_KEYWORD"); if (!vsGlobalKeyword) { - this->WriteString("<Keyword>Win32Proj</Keyword>\n", 2); + this->WriteElem("Keyword", "Win32Proj", 2); } else { - this->WriteString("<Keyword>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(vsGlobalKeyword) - << "</Keyword>\n"; + this->WriteElemEscapeXML("Keyword", vsGlobalKeyword, 2); } const char* vsGlobalRootNamespace = this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE"); if (vsGlobalRootNamespace) { - this->WriteString("<RootNamespace>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(vsGlobalRootNamespace) - << "</RootNamespace>\n"; + this->WriteElemEscapeXML("RootNamespace", vsGlobalRootNamespace, 2); } - this->WriteString("<Platform>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(this->Platform) - << "</Platform>\n"; + this->WriteElemEscapeXML("Platform", this->Platform, 2); const char* projLabel = this->GeneratorTarget->GetProperty("PROJECT_LABEL"); if (!projLabel) { projLabel = this->Name.c_str(); } - this->WriteString("<ProjectName>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(projLabel) << "</ProjectName>\n"; + this->WriteElemEscapeXML("ProjectName", projLabel, 2); if (const char* targetFrameworkVersion = this->GeneratorTarget->GetProperty( "VS_DOTNET_TARGET_FRAMEWORK_VERSION")) { - this->WriteString("<TargetFrameworkVersion>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(targetFrameworkVersion) - << "</TargetFrameworkVersion>\n"; + this->WriteElemEscapeXML("TargetFrameworkVersion", targetFrameworkVersion, + 2); } // Disable the project upgrade prompt that is displayed the first time a @@ -385,9 +417,7 @@ void cmVisualStudio10TargetGenerator::Generate() // the IDE (respected by VS 2013 and above). if (this->GlobalGenerator->GetVersion() >= cmGlobalVisualStudioGenerator::VS12) { - this->WriteString("<VCProjectUpgraderObjectName>NoUpgrade" - "</VCProjectUpgraderObjectName>\n", - 2); + this->WriteElem("VCProjectUpgraderObjectName", "NoUpgrade", 2); } std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys(); @@ -438,8 +468,7 @@ void cmVisualStudio10TargetGenerator::Generate() } outputType += "</OutputType>\n"; this->WriteString(outputType.c_str(), 2); - this->WriteString("<AppDesignerFolder>Properties</AppDesignerFolder>\n", - 2); + this->WriteElem("AppDesignerFolder", "Properties", 2); } this->WriteString("</PropertyGroup>\n", 1); @@ -602,8 +631,7 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferences() if (!name.empty()) { std::string path = i.second.GetValue(); if (!cmsys::SystemTools::FileIsFullPath(path)) { - path = std::string(this->GeneratorTarget->Target->GetMakefile() - ->GetCurrentSourceDirectory()) + + path = std::string(this->Makefile->GetCurrentSourceDirectory()) + "/" + path; } ConvertToWindowsSlash(path); @@ -637,12 +665,8 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReference( { this->WriteString("<Reference Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(ref) << "\">\n"; - this->WriteString("<CopyLocalSatelliteAssemblies>true" - "</CopyLocalSatelliteAssemblies>\n", - 3); - this->WriteString("<ReferenceOutputAssembly>true" - "</ReferenceOutputAssembly>\n", - 3); + this->WriteElem("CopyLocalSatelliteAssemblies", "true", 3); + this->WriteElem("ReferenceOutputAssembly", "true", 3); if (!hint.empty()) { const char* privateReference = "True"; if (const char* value = this->GeneratorTarget->GetProperty( @@ -651,10 +675,8 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReference( privateReference = "False"; } } - this->WriteString("<Private>", 3); - (*this->BuildFileStream) << privateReference << "</Private>\n"; - this->WriteString("<HintPath>", 3); - (*this->BuildFileStream) << hint << "</HintPath>\n"; + this->WriteElem("Private", privateReference, 3); + this->WriteElem("HintPath", hint, 3); } this->WriteDotNetReferenceCustomTags(ref); this->WriteString("</Reference>\n", 2); @@ -713,9 +735,8 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() (*this->BuildFileStream) << obj << "\">\n"; if (this->ProjectType != csproj) { - this->WriteString("<DependentUpon>", 3); std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h"; - (*this->BuildFileStream) << hFileName << "</DependentUpon>\n"; + this->WriteElem("DependentUpon", hFileName, 3); for (std::string const& i : this->Configurations) { this->WritePlatformConfigTag("LogicalName", i, 3); @@ -743,8 +764,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() link = cmsys::SystemTools::GetFilenameName(obj); } if (!link.empty()) { - this->WriteString("<Link>", 3); - (*this->BuildFileStream) << link << "</Link>\n"; + this->WriteElem("Link", link, 3); } } // Determine if this is a generated resource from a .Designer.cs file @@ -758,9 +778,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() generator = g; } if (!generator.empty()) { - this->WriteString("<Generator>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(generator) - << "</Generator>\n"; + this->WriteElemEscapeXML("Generator", generator, 3); if (designerResource.find(srcDir) == 0) { designerResource = designerResource.substr(srcDir.length() + 1); } else if (designerResource.find(binDir) == 0) { @@ -770,9 +788,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() cmsys::SystemTools::GetFilenameName(designerResource); } ConvertToWindowsSlash(designerResource); - this->WriteString("<LastGenOutput>", 3); - (*this->BuildFileStream) << designerResource - << "</LastGenOutput>\n"; + this->WriteElem("LastGenOutput", designerResource, 3); } } const cmPropertyMap& props = oi->GetProperties(); @@ -807,7 +823,7 @@ void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup() this->WriteString("<ItemGroup>\n", 1); for (cmSourceFile const* oi : xamlObjs) { std::string obj = oi->GetFullPath(); - std::string xamlType; + const char* xamlType; const char* xamlTypeProperty = oi->GetProperty("VS_XAML_TYPE"); if (xamlTypeProperty) { xamlType = xamlTypeProperty; @@ -815,7 +831,9 @@ void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup() xamlType = "Page"; } - this->WriteSource(xamlType, oi, ">\n"); + Elem e2(*this->BuildFileStream, 2); + this->WriteSource(xamlType, oi); + e2.SetHasElements(); if (this->ProjectType == csproj && !this->InSourceBuild) { // add <Link> tag to written XAML source if necessary const std::string srcDir = this->Makefile->GetCurrentSourceDirectory(); @@ -830,13 +848,11 @@ void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup() } if (!link.empty()) { ConvertToWindowsSlash(link); - this->WriteString("<Link>", 3); - (*this->BuildFileStream) << link << "</Link>\n"; + this->WriteElem("Link", link, 3); } } - this->WriteString("<SubType>Designer</SubType>\n", 3); - this->WriteString("</", 2); - (*this->BuildFileStream) << xamlType << ">\n"; + this->WriteElem("SubType", "Designer", 3); + e2.WriteEndTag(xamlType); } this->WriteString("</ItemGroup>\n", 1); } @@ -858,10 +874,7 @@ void cmVisualStudio10TargetGenerator::WriteTargetSpecificReferences() void cmVisualStudio10TargetGenerator::WriteTargetsFileReferences() { - for (std::vector<TargetsFileAndConfigs>::iterator i = - this->TargetsFileAndConfigsVec.begin(); - i != this->TargetsFileAndConfigsVec.end(); ++i) { - TargetsFileAndConfigs const& tac = *i; + for (TargetsFileAndConfigs const& tac : this->TargetsFileAndConfigsVec) { this->WriteString("<Import Project=\"", 3); (*this->BuildFileStream) << tac.File << "\" "; (*this->BuildFileStream) << "Condition=\""; @@ -896,11 +909,10 @@ void cmVisualStudio10TargetGenerator::WriteWinRTReferences() } if (!references.empty()) { this->WriteString("<ItemGroup>\n", 1); - for (std::vector<std::string>::iterator ri = references.begin(); - ri != references.end(); ++ri) { + for (std::string const& ri : references) { this->WriteString("<Reference Include=\"", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(*ri) << "\">\n"; - this->WriteString("<IsWinMDFile>true</IsWinMDFile>\n", 3); + (*this->BuildFileStream) << cmVS10EscapeXML(ri) << "\">\n"; + this->WriteElem("IsWinMDFile", "true", 3); this->WriteString("</Reference>\n", 2); } this->WriteString("</ItemGroup>\n", 1); @@ -912,16 +924,11 @@ void cmVisualStudio10TargetGenerator::WriteWinRTReferences() void cmVisualStudio10TargetGenerator::WriteProjectConfigurations() { this->WriteString("<ItemGroup Label=\"ProjectConfigurations\">\n", 1); - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { + for (std::string const& c : this->Configurations) { this->WriteString("<ProjectConfiguration Include=\"", 2); - (*this->BuildFileStream) << *i << "|" << this->Platform << "\">\n"; - this->WriteString("<Configuration>", 3); - (*this->BuildFileStream) << *i << "</Configuration>\n"; - this->WriteString("<Platform>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(this->Platform) - << "</Platform>\n"; + (*this->BuildFileStream) << c << "|" << this->Platform << "\">\n"; + this->WriteElem("Configuration", c, 3); + this->WriteElemEscapeXML("Platform", this->Platform, 3); this->WriteString("</ProjectConfiguration>\n", 2); } this->WriteString("</ItemGroup>\n", 1); @@ -929,10 +936,8 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurations() void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() { - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - this->WritePlatformConfigTag("PropertyGroup", *i, 1, + for (std::string const& c : this->Configurations) { + this->WritePlatformConfigTag("PropertyGroup", c, 1, " Label=\"Configuration\"", "\n"); if (this->ProjectType != csproj) { @@ -979,12 +984,12 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() if (this->MSTools) { if (!this->Managed) { - this->WriteMSToolConfigurationValues(*i); + this->WriteMSToolConfigurationValues(c); } else { - this->WriteMSToolConfigurationValuesManaged(*i); + this->WriteMSToolConfigurationValuesManaged(c); } } else if (this->NsightTegra) { - this->WriteNsightTegraConfigurationValues(*i); + this->WriteNsightTegraConfigurationValues(c); } this->WriteString("</PropertyGroup>\n", 1); @@ -994,11 +999,8 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues( std::string const& config) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); - const char* mfcFlag = - this->GeneratorTarget->Target->GetMakefile()->GetDefinition( - "CMAKE_MFC_FLAG"); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; + const char* mfcFlag = this->Makefile->GetDefinition("CMAKE_MFC_FLAG"); if (mfcFlag) { std::string const mfcFlagValue = mfcFlag; @@ -1010,9 +1012,7 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues( useOfMfcValue = "Dynamic"; } } - std::string mfcLine = "<UseOfMfc>"; - mfcLine += useOfMfcValue + "</UseOfMfc>\n"; - this->WriteString(mfcLine.c_str(), 2); + this->WriteElem("UseOfMfc", useOfMfcValue, 2); } if ((this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY && @@ -1021,57 +1021,46 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues( this->GlobalGenerator->TargetsWindowsPhone() || this->GlobalGenerator->TargetsWindowsStore() || this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) { - this->WriteString("<CharacterSet>Unicode</CharacterSet>\n", 2); + this->WriteElem("CharacterSet", "Unicode", 2); } else if (this->GeneratorTarget->GetType() <= cmStateEnums::MODULE_LIBRARY && this->ClOptions[config]->UsingSBCS()) { - this->WriteString("<CharacterSet>NotSet</CharacterSet>\n", 2); + this->WriteElem("CharacterSet", "NotSet", 2); } else { - this->WriteString("<CharacterSet>MultiByte</CharacterSet>\n", 2); + this->WriteElem("CharacterSet", "MultiByte", 2); } if (const char* toolset = gg->GetPlatformToolset()) { - std::string pts = "<PlatformToolset>"; - pts += toolset; - pts += "</PlatformToolset>\n"; - this->WriteString(pts.c_str(), 2); + this->WriteElem("PlatformToolset", toolset, 2); } if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT") || this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) { - this->WriteString("<WindowsAppContainer>true" - "</WindowsAppContainer>\n", - 2); + this->WriteElem("WindowsAppContainer", "true", 2); } } void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged( std::string const& config) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; Options& o = *(this->ClOptions[config]); if (o.IsDebug()) { - this->WriteString("<DebugSymbols>true</DebugSymbols>\n", 2); - this->WriteString("<DefineDebug>true</DefineDebug>\n", 2); + this->WriteElem("DebugSymbols", "true", 2); + this->WriteElem("DefineDebug", "true", 2); } std::string outDir = this->GeneratorTarget->GetDirectory(config) + "/"; ConvertToWindowsSlash(outDir); - this->WriteString("<OutputPath>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(outDir) << "</OutputPath>\n"; + this->WriteElemEscapeXML("OutputPath", outDir, 2); if (o.HasFlag("Platform")) { - this->WriteString("<PlatformTarget>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(o.GetFlag("Platform")) - << "</PlatformTarget>\n"; + this->WriteElemEscapeXML("PlatformTarget", o.GetFlag("Platform"), 2); o.RemoveFlag("Platform"); } if (const char* toolset = gg->GetPlatformToolset()) { - this->WriteString("<PlatformToolset>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(toolset) - << "</PlatformToolset>\n"; + this->WriteElemEscapeXML("PlatformToolset", toolset, 2); } std::string postfixName = cmSystemTools::UpperCase(config); @@ -1081,12 +1070,10 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged( if (const char* postfix = this->GeneratorTarget->GetProperty(postfixName)) { assemblyName += postfix; } - this->WriteString("<AssemblyName>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(assemblyName) - << "</AssemblyName>\n"; + this->WriteElemEscapeXML("AssemblyName", assemblyName, 2); if (cmStateEnums::EXECUTABLE == this->GeneratorTarget->GetType()) { - this->WriteString("<StartAction>Program</StartAction>\n", 2); + this->WriteElem("StartAction", "Program", 2); this->WriteString("<StartProgram>", 2); (*this->BuildFileStream) << cmVS10EscapeXML(outDir) << cmVS10EscapeXML(assemblyName) @@ -1100,8 +1087,7 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged( void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues( std::string const&) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; const char* toolset = gg->GetPlatformToolset(); std::string ntv = "<NdkToolchainVersion>"; ntv += toolset ? toolset : "Default"; @@ -1109,27 +1095,20 @@ void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues( this->WriteString(ntv.c_str(), 2); if (const char* minApi = this->GeneratorTarget->GetProperty("ANDROID_API_MIN")) { - this->WriteString("<AndroidMinAPI>", 2); - (*this->BuildFileStream) << "android-" << cmVS10EscapeXML(minApi) - << "</AndroidMinAPI>\n"; + this->WriteElem("AndroidMinAPI", "android-" + cmVS10EscapeXML(minApi), 2); } if (const char* api = this->GeneratorTarget->GetProperty("ANDROID_API")) { - this->WriteString("<AndroidTargetAPI>", 2); - (*this->BuildFileStream) << "android-" << cmVS10EscapeXML(api) - << "</AndroidTargetAPI>\n"; + this->WriteElem("AndroidTargetAPI", "android-" + cmVS10EscapeXML(api), 2); } if (const char* cpuArch = this->GeneratorTarget->GetProperty("ANDROID_ARCH")) { - this->WriteString("<AndroidArch>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(cpuArch) << "</AndroidArch>\n"; + this->WriteElemEscapeXML("AndroidArch", cpuArch, 2); } if (const char* stlType = this->GeneratorTarget->GetProperty("ANDROID_STL_TYPE")) { - this->WriteString("<AndroidStlType>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(stlType) - << "</AndroidStlType>\n"; + this->WriteElemEscapeXML("AndroidStlType", stlType, 2); } } @@ -1139,10 +1118,8 @@ void cmVisualStudio10TargetGenerator::WriteCustomCommands() this->CSharpCustomCommandNames.clear(); std::vector<cmSourceFile const*> customCommands; this->GeneratorTarget->GetCustomCommands(customCommands, ""); - for (std::vector<cmSourceFile const*>::const_iterator si = - customCommands.begin(); - si != customCommands.end(); ++si) { - this->WriteCustomCommand(*si); + for (cmSourceFile const* si : customCommands) { + this->WriteCustomCommand(si); } // Add CMakeLists.txt file with rule to re-run CMake for user convenience. @@ -1161,9 +1138,8 @@ void cmVisualStudio10TargetGenerator::WriteCustomCommand( if (this->SourcesVisited.insert(sf).second) { if (std::vector<cmSourceFile*> const* depends = this->GeneratorTarget->GetSourceDepends(sf)) { - for (std::vector<cmSourceFile*>::const_iterator di = depends->begin(); - di != depends->end(); ++di) { - this->WriteCustomCommand(*di); + for (cmSourceFile const* di : *depends) { + this->WriteCustomCommand(di); } } if (cmCustomCommand const* command = sf->GetCustomCommand()) { @@ -1186,10 +1162,10 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( // VS 10 will always rebuild a custom command attached to a .rule // file that doesn't exist so create the file explicitly. if (source->GetPropertyAsBool("__CMAKE_RULE")) { - if (!cmSystemTools::FileExists(sourcePath.c_str())) { + if (!cmSystemTools::FileExists(sourcePath)) { // Make sure the path exists for the file std::string path = cmSystemTools::GetFilenamePath(sourcePath); - cmSystemTools::MakeDirectory(path.c_str()); + cmSystemTools::MakeDirectory(path); cmsys::ofstream fout(sourcePath.c_str()); if (fout) { fout << "# generated from CMake\n"; @@ -1209,34 +1185,33 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( } cmLocalVisualStudio7Generator* lg = this->LocalGenerator; + Elem e2(*this->BuildFileStream, 2); if (this->ProjectType != csproj) { - this->WriteSource("CustomBuild", source, ">\n"); + this->WriteSource("CustomBuild", source); + e2.SetHasElements(); } else { this->WriteString("<ItemGroup>\n", 1); std::string link; this->GetCSharpSourceLink(source, link); - this->WriteSource("None", source, ">\n"); + this->WriteSource("None", source); + e2.SetHasElements(); if (!link.empty()) { - this->WriteString("<Link>", 3); - (*this->BuildFileStream) << link << "</Link>\n"; + this->WriteElem("Link", link, 3); } - this->WriteString("</None>\n", 2); + e2.WriteEndTag("None"); this->WriteString("</ItemGroup>\n", 1); } - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - cmCustomCommandGenerator ccg(command, *i, this->LocalGenerator); + for (std::string const& c : this->Configurations) { + cmCustomCommandGenerator ccg(command, c, lg); std::string comment = lg->ConstructComment(ccg); comment = cmVS10EscapeComment(comment); std::string script = cmVS10EscapeXML(lg->ConstructScript(ccg)); // input files for custom command std::stringstream inputs; inputs << cmVS10EscapeXML(source->GetFullPath()); - for (std::vector<std::string>::const_iterator d = ccg.GetDepends().begin(); - d != ccg.GetDepends().end(); ++d) { + for (std::string const& d : ccg.GetDepends()) { std::string dep; - if (this->LocalGenerator->GetRealDependency(*d, *i, dep)) { + if (lg->GetRealDependency(d, c, dep)) { ConvertToWindowsSlash(dep); inputs << ";" << cmVS10EscapeXML(dep); } @@ -1244,15 +1219,14 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( // output files for custom command std::stringstream outputs; const char* sep = ""; - for (std::vector<std::string>::const_iterator o = ccg.GetOutputs().begin(); - o != ccg.GetOutputs().end(); ++o) { - std::string out = *o; + for (std::string const& o : ccg.GetOutputs()) { + std::string out = o; ConvertToWindowsSlash(out); outputs << sep << cmVS10EscapeXML(out); sep = ";"; } if (this->ProjectType == csproj) { - std::string name = "CustomCommand_" + *i + "_" + + std::string name = "CustomCommand_" + c + "_" + cmSystemTools::ComputeStringMD5(sourcePath); std::string inputs_s = inputs.str(); std::string outputs_s = outputs.str(); @@ -1260,15 +1234,15 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( script = cmVS10EscapeQuotes(script); inputs_s = cmVS10EscapeQuotes(inputs_s); outputs_s = cmVS10EscapeQuotes(outputs_s); - this->WriteCustomRuleCSharp(*i, name, script, inputs_s, outputs_s, + this->WriteCustomRuleCSharp(c, name, script, inputs_s, outputs_s, comment); } else { - this->WriteCustomRuleCpp(*i, script, inputs.str(), outputs.str(), + this->WriteCustomRuleCpp(c, script, inputs.str(), outputs.str(), comment); } } if (this->ProjectType != csproj) { - this->WriteString("</CustomBuild>\n", 2); + e2.WriteEndTag("CustomBuild"); } } @@ -1321,8 +1295,8 @@ std::string cmVisualStudio10TargetGenerator::ConvertPath( { return forceRelative ? cmSystemTools::RelativePath( - this->LocalGenerator->GetCurrentBinaryDirectory(), path.c_str()) - : path.c_str(); + this->LocalGenerator->GetCurrentBinaryDirectory(), path) + : path; } static void ConvertToWindowsSlash(std::string& s) @@ -1334,6 +1308,7 @@ static void ConvertToWindowsSlash(std::string& s) pos++; } } + void cmVisualStudio10TargetGenerator::WriteGroups() { if (this->ProjectType == csproj) { @@ -1347,10 +1322,8 @@ void cmVisualStudio10TargetGenerator::WriteGroups() this->GeneratorTarget->GetAllConfigSources(); std::set<cmSourceGroup*> groupsUsed; - for (std::vector<cmGeneratorTarget::AllConfigSource>::const_iterator si = - sources.begin(); - si != sources.end(); ++si) { - std::string const& source = si->Source->GetFullPath(); + for (cmGeneratorTarget::AllConfigSource const& si : sources) { + std::string const& source = si.Source->GetFullPath(); cmSourceGroup* sourceGroup = this->Makefile->FindSourceGroup(source, sourceGroups); groupsUsed.insert(sourceGroup); @@ -1382,9 +1355,8 @@ void cmVisualStudio10TargetGenerator::WriteGroups() "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"); this->WriteString(project_defaults.c_str(), 0); - for (ToolSourceMap::const_iterator ti = this->Tools.begin(); - ti != this->Tools.end(); ++ti) { - this->WriteGroupSources(ti->first.c_str(), ti->second, sourceGroups); + for (auto const& ti : this->Tools) { + this->WriteGroupSources(ti.first.c_str(), ti.second, sourceGroups); } // Added files are images and the manifest. @@ -1396,23 +1368,23 @@ void cmVisualStudio10TargetGenerator::WriteGroups() if (fileName == "wmappmanifest.xml") { this->WriteString("<XML Include=\"", 2); (*this->BuildFileStream) << oi << "\">\n"; - this->WriteString("<Filter>Resource Files</Filter>\n", 3); + this->WriteElem("Filter", "Resource Files", 3); this->WriteString("</XML>\n", 2); } else if (cmSystemTools::GetFilenameExtension(fileName) == ".appxmanifest") { this->WriteString("<AppxManifest Include=\"", 2); (*this->BuildFileStream) << oi << "\">\n"; - this->WriteString("<Filter>Resource Files</Filter>\n", 3); + this->WriteElem("Filter", "Resource Files", 3); this->WriteString("</AppxManifest>\n", 2); } else if (cmSystemTools::GetFilenameExtension(fileName) == ".pfx") { this->WriteString("<None Include=\"", 2); (*this->BuildFileStream) << oi << "\">\n"; - this->WriteString("<Filter>Resource Files</Filter>\n", 3); + this->WriteElem("Filter", "Resource Files", 3); this->WriteString("</None>\n", 2); } else { this->WriteString("<Image Include=\"", 2); (*this->BuildFileStream) << oi << "\">\n"; - this->WriteString("<Filter>Resource Files</Filter>\n", 3); + this->WriteElem("Filter", "Resource Files", 3); this->WriteString("</Image>\n", 2); } } @@ -1428,7 +1400,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups() this->WriteString("<EmbeddedResource Include=\"", 2); ConvertToWindowsSlash(obj); (*this->BuildFileStream) << cmVS10EscapeXML(obj) << "\">\n"; - this->WriteString("<Filter>Resource Files</Filter>\n", 3); + this->WriteElem("Filter", "Resource Files", 3); this->WriteString("</EmbeddedResource>\n", 2); } this->WriteString("</ItemGroup>\n", 1); @@ -1447,10 +1419,8 @@ void cmVisualStudio10TargetGenerator::WriteGroups() (*this->BuildFileStream) << name << "\">\n"; std::string guidName = "SG_Filter_"; guidName += name; - this->WriteString("<UniqueIdentifier>", 3); std::string guid = this->GlobalGenerator->GetGUID(guidName); - (*this->BuildFileStream) << "{" << guid << "}" - << "</UniqueIdentifier>\n"; + this->WriteElem("UniqueIdentifier", "{" + guid + "}", 3); this->WriteString("</Filter>\n", 2); } } @@ -1458,10 +1428,8 @@ void cmVisualStudio10TargetGenerator::WriteGroups() if (!resxObjs.empty() || !this->AddedFiles.empty()) { this->WriteString("<Filter Include=\"Resource Files\">\n", 2); std::string guidName = "SG_Filter_Resource Files"; - this->WriteString("<UniqueIdentifier>", 3); std::string guid = this->GlobalGenerator->GetGUID(guidName); - (*this->BuildFileStream) << "{" << guid << "}" - << "</UniqueIdentifier>\n"; + this->WriteElem("UniqueIdentifier", "{" + guid + "}", 3); this->WriteString("<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;", 3); (*this->BuildFileStream) << "gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;"; (*this->BuildFileStream) << "mfcribbon-ms</Extensions>\n"; @@ -1516,7 +1484,7 @@ void cmVisualStudio10TargetGenerator::AddMissingSourceGroups( } void cmVisualStudio10TargetGenerator::WriteGroupSources( - const char* name, ToolSources const& sources, + std::string const& name, ToolSources const& sources, std::vector<cmSourceGroup>& sourceGroups) { this->WriteString("<ItemGroup>\n", 1); @@ -1532,8 +1500,7 @@ void cmVisualStudio10TargetGenerator::WriteGroupSources( (*this->BuildFileStream) << name << " Include=\"" << cmVS10EscapeXML(path); if (!filter.empty()) { (*this->BuildFileStream) << "\">\n"; - this->WriteString("<Filter>", 3); - (*this->BuildFileStream) << filter << "</Filter>\n"; + this->WriteElem("Filter", filter, 3); this->WriteString("</", 2); (*this->BuildFileStream) << name << ">\n"; } else { @@ -1546,25 +1513,23 @@ void cmVisualStudio10TargetGenerator::WriteGroupSources( void cmVisualStudio10TargetGenerator::WriteHeaderSource(cmSourceFile const* sf) { std::string const& fileName = sf->GetFullPath(); + Elem e2(*this->BuildFileStream, 2); + this->WriteSource("ClInclude", sf); if (this->IsResxHeader(fileName)) { - this->WriteSource("ClInclude", sf, ">\n"); - this->WriteString("<FileType>CppForm</FileType>\n", 3); - this->WriteString("</ClInclude>\n", 2); + e2.SetHasElements(); + this->WriteElem("FileType", "CppForm", 3); } else if (this->IsXamlHeader(fileName)) { - this->WriteSource("ClInclude", sf, ">\n"); - this->WriteString("<DependentUpon>", 3); std::string xamlFileName = fileName.substr(0, fileName.find_last_of(".")); - (*this->BuildFileStream) << xamlFileName << "</DependentUpon>\n"; - this->WriteString("</ClInclude>\n", 2); - } else { - this->WriteSource("ClInclude", sf); + e2.SetHasElements(); + this->WriteElem("DependentUpon", xamlFileName, 3); } + e2.WriteEndTag("ClInclude"); } void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) { bool toolHasSettings = false; - std::string tool = "None"; + const char* tool = "None"; std::string shaderType; std::string shaderEntryPoint; std::string shaderModel; @@ -1714,8 +1679,10 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) } } + Elem e2(*this->BuildFileStream, 2); + this->WriteSource(tool, sf); if (toolHasSettings) { - this->WriteSource(tool, sf, ">\n"); + e2.SetHasElements(); if (!deployContent.empty()) { cmGeneratorExpression ge; @@ -1749,19 +1716,13 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) } } if (!shaderType.empty()) { - this->WriteString("<ShaderType>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(shaderType) - << "</ShaderType>\n"; + this->WriteElemEscapeXML("ShaderType", shaderType, 3); } if (!shaderEntryPoint.empty()) { - this->WriteString("<EntryPointName>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(shaderEntryPoint) - << "</EntryPointName>\n"; + this->WriteElemEscapeXML("EntryPointName", shaderEntryPoint, 3); } if (!shaderModel.empty()) { - this->WriteString("<ShaderModel>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(shaderModel) - << "</ShaderModel>\n"; + this->WriteElemEscapeXML("ShaderModel", shaderModel, 3); } if (!outputHeaderFile.empty()) { for (size_t i = 0; i != this->Configurations.size(); ++i) { @@ -1786,60 +1747,42 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) } } if (!shaderEnableDebug.empty()) { - this->WriteString("<EnableDebuggingInformation>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(shaderEnableDebug) - << "</EnableDebuggingInformation>\n"; + this->WriteElemEscapeXML("EnableDebuggingInformation", shaderEnableDebug, + 3); } if (!shaderDisableOptimizations.empty()) { - this->WriteString("<DisableOptimizations>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(shaderDisableOptimizations) - << "</DisableOptimizations>\n"; + this->WriteElemEscapeXML("DisableOptimizations", + shaderDisableOptimizations, 3); } if (!shaderAdditionalFlags.empty()) { - this->WriteString("<AdditionalOptions>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(shaderAdditionalFlags) - << "</AdditionalOptions>\n"; + this->WriteElemEscapeXML("AdditionalOptions", shaderAdditionalFlags, 3); } if (!settingsGenerator.empty()) { - this->WriteString("<Generator>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(settingsGenerator) - << "</Generator>\n"; + this->WriteElemEscapeXML("Generator", settingsGenerator, 3); } if (!settingsLastGenOutput.empty()) { - this->WriteString("<LastGenOutput>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(settingsLastGenOutput) - << "</LastGenOutput>\n"; + this->WriteElemEscapeXML("LastGenOutput", settingsLastGenOutput, 3); } if (!sourceLink.empty()) { - this->WriteString("<Link>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(sourceLink) << "</Link>\n"; + this->WriteElemEscapeXML("Link", sourceLink, 3); } if (!subType.empty()) { - this->WriteString("<SubType>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(subType) << "</SubType>\n"; + this->WriteElemEscapeXML("SubType", subType, 3); } if (!copyToOutDir.empty()) { - this->WriteString("<CopyToOutputDirectory>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(copyToOutDir) - << "</CopyToOutputDirectory>\n"; + this->WriteElemEscapeXML("CopyToOutputDirectory", copyToOutDir, 3); } if (!includeInVsix.empty()) { - this->WriteString("<IncludeInVSIX>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(includeInVsix) - << "</IncludeInVSIX>\n"; + this->WriteElemEscapeXML("IncludeInVSIX", includeInVsix, 3); } // write source file specific tags this->WriteCSharpSourceProperties(sourceFileTags); - this->WriteString("</", 2); - (*this->BuildFileStream) << tool << ">\n"; - } else { - this->WriteSource(tool, sf); } + e2.WriteEndTag(tool); } void cmVisualStudio10TargetGenerator::WriteSource(std::string const& tool, - cmSourceFile const* sf, - const char* end) + cmSourceFile const* sf) { // Visual Studio tools append relative paths to the current dir, as in: // @@ -1853,7 +1796,7 @@ void cmVisualStudio10TargetGenerator::WriteSource(std::string const& tool, std::string sourceFile = this->ConvertPath(sf->GetFullPath(), forceRelative); if (this->LocalGenerator->GetVersion() == cmGlobalVisualStudioGenerator::VS10 && - cmSystemTools::FileIsFullPath(sourceFile.c_str())) { + cmSystemTools::FileIsFullPath(sourceFile)) { // Normal path conversion resulted in a full path. VS 10 (but not 11) // refuses to show the property page in the IDE for a source file with a // full path (not starting in a '.' or '/' AFAICT). CMake <= 2.8.4 used a @@ -1876,8 +1819,7 @@ void cmVisualStudio10TargetGenerator::WriteSource(std::string const& tool, ConvertToWindowsSlash(sourceFile); this->WriteString("<", 2); (*this->BuildFileStream) << tool << " Include=\"" - << cmVS10EscapeXML(sourceFile) << "\"" - << (end ? end : " />\n"); + << cmVS10EscapeXML(sourceFile) << "\""; ToolSource toolSource = { sf, forceRelative }; this->Tools[tool].push_back(toolSource); @@ -1899,7 +1841,7 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() this->GeneratorTarget->GetAllConfigSources(); for (cmGeneratorTarget::AllConfigSource const& si : sources) { - std::string tool; + const char* tool = nullptr; switch (si.Kind) { case cmGeneratorTarget::SourceKindAppManifest: tool = "AppxManifest"; @@ -1968,7 +1910,7 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() break; } - if (!tool.empty()) { + if (tool) { // Compute set of configurations to exclude, if any. std::vector<size_t> const& include_configs = si.Configs; std::vector<size_t> exclude_configs; @@ -1976,31 +1918,15 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() include_configs.begin(), include_configs.end(), std::back_inserter(exclude_configs)); + Elem e2(*this->BuildFileStream, 2); + this->WriteSource(tool, si.Source); if (si.Kind == cmGeneratorTarget::SourceKindObjectSource) { - // FIXME: refactor generation to avoid tracking XML syntax state. - this->WriteSource(tool, si.Source, ""); - bool have_nested = this->OutputSourceSpecificFlags(si.Source); - if (!exclude_configs.empty()) { - if (!have_nested) { - (*this->BuildFileStream) << ">\n"; - } - this->WriteExcludeFromBuild(exclude_configs); - have_nested = true; - } - if (have_nested) { - this->WriteString("</", 2); - (*this->BuildFileStream) << tool << ">\n"; - } else { - (*this->BuildFileStream) << " />\n"; - } - } else if (!exclude_configs.empty()) { - this->WriteSource(tool, si.Source, ">\n"); - this->WriteExcludeFromBuild(exclude_configs); - this->WriteString("</", 2); - (*this->BuildFileStream) << tool << ">\n"; - } else { - this->WriteSource(tool, si.Source); + this->OutputSourceSpecificFlags(e2, si.Source); } + if (!exclude_configs.empty()) { + this->WriteExcludeFromBuild(e2, exclude_configs); + } + e2.WriteEndTag(tool); } } @@ -2011,8 +1937,8 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() this->WriteString("</ItemGroup>\n", 1); } -bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( - cmSourceFile const* source) +void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( + Elem& e2, cmSourceFile const* source) { cmSourceFile const& sf = *source; @@ -2072,22 +1998,14 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( } } bool noWinRT = this->TargetCompileAsWinRT && lang == "C"; - bool hasFlags = false; // for the first time we need a new line if there is something // produced here. - const char* firstString = ">\n"; if (!objectName.empty()) { - (*this->BuildFileStream) << firstString; - firstString = ""; - hasFlags = true; + e2.SetHasElements(); if (lang == "CUDA") { - this->WriteString("<CompileOut>", 3); - (*this->BuildFileStream) << "$(IntDir)/" << objectName - << "</CompileOut>\n"; + this->WriteElem("CompileOut", "$(IntDir)/" + objectName, 3); } else { - this->WriteString("<ObjectFileName>", 3); - (*this->BuildFileStream) << "$(IntDir)/" << objectName - << "</ObjectFileName>\n"; + this->WriteElem("ObjectFileName", "$(IntDir)/" + objectName, 3); } } for (std::string const& config : this->Configurations) { @@ -2107,11 +2025,8 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( // use them if (!flags.empty() || !options.empty() || !configDefines.empty() || !includes.empty() || compileAs || noWinRT) { - (*this->BuildFileStream) << firstString; - firstString = ""; // only do firstString once - hasFlags = true; - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + e2.SetHasElements(); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; cmIDEFlagTable const* flagtable = nullptr; const std::string& srclang = source->GetLanguage(); if (srclang == "C" || srclang == "CXX") { @@ -2163,7 +2078,7 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( clOptions.AddDefines( genexInterpreter.Evaluate(configDefines, "COMPILE_DEFINITIONS")); } else { - clOptions.AddDefines(configDefines.c_str()); + clOptions.AddDefines(configDefines); } std::vector<std::string> includeList; if (configDependentIncludes) { @@ -2175,7 +2090,7 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( *source); } clOptions.AddIncludes(includeList); - clOptions.SetConfiguration(config.c_str()); + clOptions.SetConfiguration(config); clOptions.PrependInheritedString("AdditionalOptions"); clOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream, " ", "\n", lang); @@ -2185,13 +2100,10 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( } } if (this->IsXamlSource(source->GetFullPath())) { - (*this->BuildFileStream) << firstString; - firstString = ""; // only do firstString once - hasFlags = true; - this->WriteString("<DependentUpon>", 3); + e2.SetHasElements(); const std::string& fileName = source->GetFullPath(); std::string xamlFileName = fileName.substr(0, fileName.find_last_of(".")); - (*this->BuildFileStream) << xamlFileName << "</DependentUpon>\n"; + this->WriteElem("DependentUpon", xamlFileName, 3); } if (this->ProjectType == csproj) { std::string f = source->GetFullPath(); @@ -2206,19 +2118,16 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( this->GetCSharpSourceProperties(&sf, sourceFileTags); // write source file specific tags if (!sourceFileTags.empty()) { - hasFlags = true; - (*this->BuildFileStream) << firstString; - firstString = ""; + e2.SetHasElements(); this->WriteCSharpSourceProperties(sourceFileTags); } } - - return hasFlags; } void cmVisualStudio10TargetGenerator::WriteExcludeFromBuild( - std::vector<size_t> const& exclude_configs) + Elem& e2, std::vector<size_t> const& exclude_configs) { + e2.SetHasElements(); for (size_t ci : exclude_configs) { this->WriteString("", 3); (*this->BuildFileStream) @@ -2239,9 +2148,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions() } this->WriteString("<PropertyGroup>\n", 1); - this->WriteString("<_ProjectFileVersion>10.0.20506.1" - "</_ProjectFileVersion>\n", - 2); + this->WriteElem("_ProjectFileVersion", "10.0.20506.1", 2); for (std::string const& config : this->Configurations) { if (ttype >= cmStateEnums::UTILITY) { this->WritePlatformConfigTag("IntDir", config, 2); @@ -2282,6 +2189,13 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions() << "</LocalDebuggerWorkingDirectory>\n"; } + if (const char* debuggerCommand = + this->GeneratorTarget->GetProperty("VS_DEBUGGER_COMMAND")) { + this->WritePlatformConfigTag("LocalDebuggerCommand", config, 2); + *this->BuildFileStream << cmVS10EscapeXML(debuggerCommand) + << "</LocalDebuggerCommand>\n"; + } + std::string name = cmSystemTools::GetFilenameWithoutLastExtension(targetNameFull); this->WritePlatformConfigTag("TargetName", config, 2); @@ -2374,8 +2288,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( // copied from cmLocalVisualStudio7Generator.cxx 805 // TODO: Integrate code below with cmLocalVisualStudio7Generator. - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; std::unique_ptr<Options> pOptions; switch (this->ProjectType) { case vcxproj: @@ -2422,15 +2335,11 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( std::string baseFlagVar = "CMAKE_"; baseFlagVar += langForClCompile; baseFlagVar += "_FLAGS"; - flags = - this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition( - baseFlagVar); + flags = this->Makefile->GetRequiredDefinition(baseFlagVar); std::string flagVar = baseFlagVar + std::string("_") + cmSystemTools::UpperCase(configName); flags += " "; - flags += - this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition( - flagVar); + flags += this->Makefile->GetRequiredDefinition(flagVar); this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, langForClCompile, configName); } @@ -2446,8 +2355,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( this->GeneratorTarget->IsIPOEnabled(linkLanguage, configName); // Get preprocessor definitions for this directory. - std::string defineFlags = - this->GeneratorTarget->Target->GetMakefile()->GetDefineFlags(); + std::string defineFlags = this->Makefile->GetDefineFlags(); if (this->MSTools) { if (this->ProjectType == vcxproj) { clOptions.FixExceptionHandlingDefault(); @@ -2552,9 +2460,7 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( if (this->NsightTegra) { if (const char* processMax = this->GeneratorTarget->GetProperty("ANDROID_PROCESS_MAX")) { - this->WriteString("<ProcessMax>", 3); - *this->BuildFileStream << cmVS10EscapeXML(processMax) - << "</ProcessMax>\n"; + this->WriteElemEscapeXML("ProcessMax", processMax, 3); } } @@ -2562,12 +2468,9 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( cmsys::RegularExpression clangToolset("v[0-9]+_clang_.*"); const char* toolset = this->GlobalGenerator->GetPlatformToolset(); if (toolset && clangToolset.find(toolset)) { - this->WriteString("<ObjectFileName>" - "$(IntDir)%(filename).obj" - "</ObjectFileName>\n", - 3); + this->WriteElem("ObjectFileName", "$(IntDir)%(filename).obj", 3); } else { - this->WriteString("<ObjectFileName>$(IntDir)</ObjectFileName>\n", 3); + this->WriteElem("ObjectFileName", "$(IntDir)", 3); } // If not in debug mode, write the DebugInformationFormat field @@ -2583,9 +2486,7 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( std::string pdb = this->GeneratorTarget->GetCompilePDBPath(configName); if (!pdb.empty()) { ConvertToWindowsSlash(pdb); - this->WriteString("<ProgramDataBaseFileName>", 3); - *this->BuildFileStream << cmVS10EscapeXML(pdb) - << "</ProgramDataBaseFileName>\n"; + this->WriteElemEscapeXML("ProgramDataBaseFileName", pdb, 3); } } @@ -2605,8 +2506,7 @@ bool cmVisualStudio10TargetGenerator::ComputeRcOptions() bool cmVisualStudio10TargetGenerator::ComputeRcOptions( std::string const& configName) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; auto pOptions = cm::make_unique<Options>( this->LocalGenerator, Options::ResourceCompiler, gg->GetRcFlagTable()); Options& rcOptions = *pOptions; @@ -2666,8 +2566,7 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions() bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( std::string const& configName) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; auto pOptions = cm::make_unique<Options>( this->LocalGenerator, Options::CudaCompiler, gg->GetCudaFlagTable()); Options& cudaOptions = *pOptions; @@ -2683,8 +2582,7 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( configName); // Get preprocessor definitions for this directory. - std::string defineFlags = - this->GeneratorTarget->Target->GetMakefile()->GetDefineFlags(); + std::string defineFlags = this->Makefile->GetDefineFlags(); cudaOptions.Parse(flags.c_str()); cudaOptions.Parse(defineFlags.c_str()); @@ -2804,8 +2702,7 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions() bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions( std::string const& configName) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; auto pOptions = cm::make_unique<Options>( this->LocalGenerator, Options::CudaCompiler, gg->GetCudaFlagTable()); Options& cudaLinkOptions = *pOptions; @@ -2873,8 +2770,7 @@ bool cmVisualStudio10TargetGenerator::ComputeMasmOptions() bool cmVisualStudio10TargetGenerator::ComputeMasmOptions( std::string const& configName) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; auto pOptions = cm::make_unique<Options>( this->LocalGenerator, Options::MasmCompiler, gg->GetMasmFlagTable()); Options& masmOptions = *pOptions; @@ -2933,8 +2829,7 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions() bool cmVisualStudio10TargetGenerator::ComputeNasmOptions( std::string const& configName) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; auto pOptions = cm::make_unique<Options>( this->LocalGenerator, Options::NasmCompiler, gg->GetNasmFlagTable()); Options& nasmOptions = *pOptions; @@ -2994,8 +2889,7 @@ void cmVisualStudio10TargetGenerator::WriteLibOptions( libflags, cmSystemTools::UpperCase(config), this->GeneratorTarget); if (!libflags.empty()) { this->WriteString("<Lib>\n", 2); - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; cmVisualStudioGeneratorOptions libOptions( this->LocalGenerator, cmVisualStudioGeneratorOptions::Linker, gg->GetLibFlagTable(), 0, this); @@ -3011,9 +2905,7 @@ void cmVisualStudio10TargetGenerator::WriteLibOptions( if (this->GlobalGenerator->TargetsWindowsPhone() || this->GlobalGenerator->TargetsWindowsStore()) { this->WriteString("<Link>\n", 2); - this->WriteString("<GenerateWindowsMetadata>false" - "</GenerateWindowsMetadata>\n", - 3); + this->WriteElem("GenerateWindowsMetadata", "false", 3); this->WriteString("</Link>\n", 2); } } @@ -3064,32 +2956,28 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( { std::string antBuildPath = rootDir; this->WriteString("<AntBuild>\n", 2); - this->WriteString("<AntBuildPath>", 3); ConvertToWindowsSlash(antBuildPath); - (*this->BuildFileStream) << cmVS10EscapeXML(antBuildPath) - << "</AntBuildPath>\n"; + this->WriteElemEscapeXML("AntBuildPath", antBuildPath, 3); } if (this->GeneratorTarget->GetPropertyAsBool("ANDROID_SKIP_ANT_STEP")) { - this->WriteString("<SkipAntStep>true</SkipAntStep>\n", 3); + this->WriteElem("SkipAntStep", "true", 3); } if (this->GeneratorTarget->GetPropertyAsBool("ANDROID_PROGUARD")) { - this->WriteString("<EnableProGuard>true</EnableProGuard>\n", 3); + this->WriteElem("EnableProGuard", "true", 3); } if (const char* proGuardConfigLocation = this->GeneratorTarget->GetProperty("ANDROID_PROGUARD_CONFIG_PATH")) { - this->WriteString("<ProGuardConfigLocation>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(proGuardConfigLocation) - << "</ProGuardConfigLocation>\n"; + this->WriteElemEscapeXML("ProGuardConfigLocation", proGuardConfigLocation, + 3); } if (const char* securePropertiesLocation = this->GeneratorTarget->GetProperty("ANDROID_SECURE_PROPS_PATH")) { - this->WriteString("<SecurePropertiesLocation>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(securePropertiesLocation) - << "</SecurePropertiesLocation>\n"; + this->WriteElemEscapeXML("SecurePropertiesLocation", + securePropertiesLocation, 3); } if (const char* nativeLibDirectoriesExpression = @@ -3099,9 +2987,7 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( ge.Parse(nativeLibDirectoriesExpression); std::string nativeLibDirs = cge->Evaluate(this->LocalGenerator, configName); - this->WriteString("<NativeLibDirectories>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(nativeLibDirs) - << "</NativeLibDirectories>\n"; + this->WriteElemEscapeXML("NativeLibDirectories", nativeLibDirs, 3); } if (const char* nativeLibDependenciesExpression = @@ -3112,16 +2998,12 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( ge.Parse(nativeLibDependenciesExpression); std::string nativeLibDeps = cge->Evaluate(this->LocalGenerator, configName); - this->WriteString("<NativeLibDependencies>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(nativeLibDeps) - << "</NativeLibDependencies>\n"; + this->WriteElemEscapeXML("NativeLibDependencies", nativeLibDeps, 3); } if (const char* javaSourceDir = this->GeneratorTarget->GetProperty("ANDROID_JAVA_SOURCE_DIR")) { - this->WriteString("<JavaSourceDir>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(javaSourceDir) - << "</JavaSourceDir>\n"; + this->WriteElemEscapeXML("JavaSourceDir", javaSourceDir, 3); } if (const char* jarDirectoriesExpression = @@ -3131,31 +3013,23 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( ge.Parse(jarDirectoriesExpression); std::string jarDirectories = cge->Evaluate(this->LocalGenerator, configName); - this->WriteString("<JarDirectories>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(jarDirectories) - << "</JarDirectories>\n"; + this->WriteElemEscapeXML("JarDirectories", jarDirectories, 3); } if (const char* jarDeps = this->GeneratorTarget->GetProperty("ANDROID_JAR_DEPENDENCIES")) { - this->WriteString("<JarDependencies>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(jarDeps) - << "</JarDependencies>\n"; + this->WriteElemEscapeXML("JarDependencies", jarDeps, 3); } if (const char* assetsDirectories = this->GeneratorTarget->GetProperty("ANDROID_ASSETS_DIRECTORIES")) { - this->WriteString("<AssetsDirectories>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(assetsDirectories) - << "</AssetsDirectories>\n"; + this->WriteElemEscapeXML("AssetsDirectories", assetsDirectories, 3); } { std::string manifest_xml = rootDir + "/AndroidManifest.xml"; ConvertToWindowsSlash(manifest_xml); - this->WriteString("<AndroidManifestLocation>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(manifest_xml) - << "</AndroidManifestLocation>\n"; + this->WriteElemEscapeXML("AndroidManifestLocation", manifest_xml, 3); } if (const char* antAdditionalOptions = @@ -3185,8 +3059,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions() bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( std::string const& config) { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; auto pOptions = cm::make_unique<Options>(this->LocalGenerator, Options::Linker, gg->GetLinkFlagTable(), nullptr, this); @@ -3217,12 +3090,10 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( linkFlagVarBase += linkType; linkFlagVarBase += "_LINKER_FLAGS"; flags += " "; - flags += this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition( - linkFlagVarBase); + flags += this->Makefile->GetRequiredDefinition(linkFlagVarBase); std::string linkFlagVar = linkFlagVarBase + "_" + CONFIG; flags += " "; - flags += this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition( - linkFlagVar); + flags += this->Makefile->GetRequiredDefinition(linkFlagVar); const char* targetLinkFlags = this->GeneratorTarget->GetProperty("LINK_FLAGS"); if (targetLinkFlags) { @@ -3376,7 +3247,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( cmGeneratorTarget::ModuleDefinitionInfo const* mdi = this->GeneratorTarget->GetModuleDefinitionInfo(config); if (mdi && !mdi->DefFile.empty()) { - linkOptions.AddFlag("ModuleDefinitionFile", mdi->DefFile.c_str()); + linkOptions.AddFlag("ModuleDefinitionFile", mdi->DefFile); } linkOptions.AppendFlag("IgnoreSpecificDefaultLibraries", "%(IgnoreSpecificDefaultLibraries)"); @@ -3459,8 +3330,7 @@ void cmVisualStudio10TargetGenerator::WriteLinkOptions( if (!this->GlobalGenerator->NeedLinkLibraryDependencies( this->GeneratorTarget)) { this->WriteString("<ProjectReference>\n", 2); - this->WriteString( - "<LinkLibraryDependencies>false</LinkLibraryDependencies>\n", 3); + this->WriteElem("LinkLibraryDependencies", "false", 3); this->WriteString("</ProjectReference>\n", 2); } } @@ -3474,6 +3344,17 @@ void cmVisualStudio10TargetGenerator::AddLibraries( std::string currentBinDir = this->LocalGenerator->GetCurrentBinaryDirectory(); for (cmComputeLinkInformation::Item const& l : libs) { + // Do not allow C# targets to be added to the LIB listing. LIB files are + // used for linking C++ dependencies. C# libraries do not have lib files. + // Instead, they compile down to C# reference libraries (DLL files). The + // `<ProjectReference>` elements added to the vcxproj are enough for the + // IDE to deduce the DLL file required by other C# projects that need its + // reference library. + if (l.Target && + cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(l.Target)) { + continue; + } + if (l.IsPath) { std::string path = this->LocalGenerator->ConvertToRelativePath(currentBinDir, l.Value); @@ -3543,15 +3424,11 @@ void cmVisualStudio10TargetGenerator::WriteMidlOptions( this->WriteString("%(AdditionalIncludeDirectories)" "</AdditionalIncludeDirectories>\n", 0); - this->WriteString("<OutputDirectory>$(ProjectDir)/$(IntDir)" - "</OutputDirectory>\n", - 3); - this->WriteString("<HeaderFileName>%(Filename).h</HeaderFileName>\n", 3); - this->WriteString("<TypeLibraryName>%(Filename).tlb</TypeLibraryName>\n", 3); - this->WriteString("<InterfaceIdentifierFileName>" - "%(Filename)_i.c</InterfaceIdentifierFileName>\n", - 3); - this->WriteString("<ProxyFileName>%(Filename)_p.c</ProxyFileName>\n", 3); + this->WriteElem("OutputDirectory", "$(ProjectDir)/$(IntDir)", 3); + this->WriteElem("HeaderFileName", "%(Filename).h", 3); + this->WriteElem("TypeLibraryName", "%(Filename).tlb", 3); + this->WriteElem("InterfaceIdentifierFileName", "%(Filename)_i.c", 3); + this->WriteElem("ProxyFileName", "%(Filename)_p.c", 3); this->WriteString("</Midl>\n", 2); } @@ -3643,8 +3520,7 @@ void cmVisualStudio10TargetGenerator::WriteEvent( } comment = cmVS10EscapeComment(comment); if (this->ProjectType != csproj) { - this->WriteString("<Message>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(comment) << "</Message>\n"; + this->WriteElemEscapeXML("Message", comment, 3); this->WriteString("<Command>", 3); } else { std::string strippedComment = comment; @@ -3679,8 +3555,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() } // skip fortran targets as they can not be processed by MSBuild // the only reference will be in the .sln file - if (static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator) - ->TargetIsFortranOnly(dt)) { + if (this->GlobalGenerator->TargetIsFortranOnly(dt)) { continue; } this->WriteString("<ProjectReference Include=\"", 2); @@ -3698,18 +3573,13 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() } ConvertToWindowsSlash(path); (*this->BuildFileStream) << cmVS10EscapeXML(path) << "\">\n"; - this->WriteString("<Project>", 3); - (*this->BuildFileStream) << "{" << this->GlobalGenerator->GetGUID(name) - << "}"; - (*this->BuildFileStream) << "</Project>\n"; - this->WriteString("<Name>", 3); - (*this->BuildFileStream) << name << "</Name>\n"; + this->WriteElem("Project", + "{" + this->GlobalGenerator->GetGUID(name) + "}", 3); + this->WriteElem("Name", name, 3); this->WriteDotNetReferenceCustomTags(name); if (csproj == this->ProjectType) { - if (!static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator) - ->TargetCanBeReferenced(dt)) { - this->WriteString( - "<ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n", 3); + if (!this->GlobalGenerator->TargetCanBeReferenced(dt)) { + this->WriteElem("ReferenceOutputAssembly", "false", 3); } } this->WriteString("</ProjectReference>\n", 2); @@ -3839,14 +3709,12 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); ConvertToWindowsSlash(artifactDir); this->WriteString("<PropertyGroup>\n", 1); - this->WriteString("<AppxPackageArtifactsDir>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(artifactDir) - << "\\</AppxPackageArtifactsDir>\n"; - this->WriteString("<ProjectPriFullPath>", 2); + this->WriteElemEscapeXML("AppxPackageArtifactsDir", artifactDir + "\\", + 2); std::string resourcePriFile = this->DefaultArtifactDir + "/resources.pri"; ConvertToWindowsSlash(resourcePriFile); - (*this->BuildFileStream) << resourcePriFile << "</ProjectPriFullPath>\n"; + this->WriteElem("ProjectPriFullPath", resourcePriFile, 2); // If we are missing files and we don't have a certificate and // aren't targeting WP8.0, add a default certificate @@ -3860,26 +3728,18 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() this->AddedFiles.push_back(pfxFile); } - this->WriteString("<", 2); - (*this->BuildFileStream) << "PackageCertificateKeyFile>" << pfxFile - << "</PackageCertificateKeyFile>\n"; + this->WriteElem("PackageCertificateKeyFile", pfxFile, 2); std::string thumb = cmSystemTools::ComputeCertificateThumbprint(pfxFile); if (!thumb.empty()) { - this->WriteString("<PackageCertificateThumbprint>", 2); - (*this->BuildFileStream) << thumb - << "</PackageCertificateThumbprint>\n"; + this->WriteElem("PackageCertificateThumbprint", thumb, 2); } this->WriteString("</PropertyGroup>\n", 1); } else if (!pfxFile.empty()) { this->WriteString("<PropertyGroup>\n", 1); - this->WriteString("<", 2); - (*this->BuildFileStream) << "PackageCertificateKeyFile>" << pfxFile - << "</PackageCertificateKeyFile>\n"; + this->WriteElem("PackageCertificateKeyFile", pfxFile, 2); std::string thumb = cmSystemTools::ComputeCertificateThumbprint(pfxFile); if (!thumb.empty()) { - this->WriteString("<PackageCertificateThumbprint>", 2); - (*this->BuildFileStream) << thumb - << "</PackageCertificateThumbprint>\n"; + this->WriteElem("PackageCertificateThumbprint", thumb, 2); } this->WriteString("</PropertyGroup>\n", 1); } @@ -3921,52 +3781,35 @@ bool cmVisualStudio10TargetGenerator::IsXamlSource( void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings() { - cmGlobalVisualStudio10Generator* gg = - static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; bool isAppContainer = false; bool const isWindowsPhone = this->GlobalGenerator->TargetsWindowsPhone(); bool const isWindowsStore = this->GlobalGenerator->TargetsWindowsStore(); std::string const& v = this->GlobalGenerator->GetSystemVersion(); if (isWindowsPhone || isWindowsStore) { - this->WriteString("<ApplicationType>", 2); - (*this->BuildFileStream) - << (isWindowsPhone ? "Windows Phone" : "Windows Store") - << "</ApplicationType>\n"; - this->WriteString("<DefaultLanguage>en-US" - "</DefaultLanguage>\n", - 2); + this->WriteElem("ApplicationType", + (isWindowsPhone ? "Windows Phone" : "Windows Store"), 2); + this->WriteElem("DefaultLanguage", "en-US", 2); if (cmHasLiteralPrefix(v, "10.0")) { - this->WriteString("<ApplicationTypeRevision>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML("10.0") - << "</ApplicationTypeRevision>\n"; + this->WriteElemEscapeXML("ApplicationTypeRevision", "10.0", 2); // Visual Studio 14.0 is necessary for building 10.0 apps - this->WriteString("<MinimumVisualStudioVersion>14.0" - "</MinimumVisualStudioVersion>\n", - 2); + this->WriteElem("MinimumVisualStudioVersion", "14.0", 2); if (this->GeneratorTarget->GetType() < cmStateEnums::UTILITY) { isAppContainer = true; } } else if (v == "8.1") { - this->WriteString("<ApplicationTypeRevision>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(v) - << "</ApplicationTypeRevision>\n"; + this->WriteElemEscapeXML("ApplicationTypeRevision", v, 2); // Visual Studio 12.0 is necessary for building 8.1 apps - this->WriteString("<MinimumVisualStudioVersion>12.0" - "</MinimumVisualStudioVersion>\n", - 2); + this->WriteElem("MinimumVisualStudioVersion", "12.0", 2); if (this->GeneratorTarget->GetType() < cmStateEnums::UTILITY) { isAppContainer = true; } } else if (v == "8.0") { - this->WriteString("<ApplicationTypeRevision>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(v) - << "</ApplicationTypeRevision>\n"; + this->WriteElemEscapeXML("ApplicationTypeRevision", v, 2); // Visual Studio 11.0 is necessary for building 8.0 apps - this->WriteString("<MinimumVisualStudioVersion>11.0" - "</MinimumVisualStudioVersion>\n", - 2); + this->WriteElem("MinimumVisualStudioVersion", "11.0", 2); if (isWindowsStore && this->GeneratorTarget->GetType() < cmStateEnums::UTILITY) { @@ -3974,52 +3817,42 @@ void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings() } else if (isWindowsPhone && this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) { - this->WriteString("<XapOutputs>true</XapOutputs>\n", 2); - this->WriteString("<XapFilename>", 2); - (*this->BuildFileStream) - << cmVS10EscapeXML(this->Name) - << "_$(Configuration)_$(Platform).xap</XapFilename>\n"; + this->WriteElem("XapOutputs", "true", 2); + this->WriteElem("XapFilename", cmVS10EscapeXML(this->Name) + + "_$(Configuration)_$(Platform).xap", + 2); } } } if (isAppContainer) { - this->WriteString("<AppContainerApplication>true" - "</AppContainerApplication>\n", - 2); + this->WriteElem("AppContainerApplication", "true", 2); } else if (this->Platform == "ARM64") { - this->WriteString("<WindowsSDKDesktopARM64Support>true" - "</WindowsSDKDesktopARM64Support>\n", - 2); + this->WriteElem("WindowsSDKDesktopARM64Support", "true", 2); } else if (this->Platform == "ARM") { - this->WriteString("<WindowsSDKDesktopARMSupport>true" - "</WindowsSDKDesktopARMSupport>\n", - 2); + this->WriteElem("WindowsSDKDesktopARMSupport", "true", 2); } std::string const& targetPlatformVersion = gg->GetWindowsTargetPlatformVersion(); if (!targetPlatformVersion.empty()) { - this->WriteString("<WindowsTargetPlatformVersion>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(targetPlatformVersion) - << "</WindowsTargetPlatformVersion>\n"; + this->WriteElemEscapeXML("WindowsTargetPlatformVersion", + targetPlatformVersion, 2); } const char* targetPlatformMinVersion = this->GeneratorTarget->GetProperty( "VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION"); if (targetPlatformMinVersion) { - this->WriteString("<WindowsTargetPlatformMinVersion>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(targetPlatformMinVersion) - << "</WindowsTargetPlatformMinVersion>\n"; + this->WriteElemEscapeXML("WindowsTargetPlatformMinVersion", + targetPlatformMinVersion, 2); } else if (isWindowsStore && cmHasLiteralPrefix(v, "10.0")) { // If the min version is not set, then use the TargetPlatformVersion if (!targetPlatformVersion.empty()) { - this->WriteString("<WindowsTargetPlatformMinVersion>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(targetPlatformVersion) - << "</WindowsTargetPlatformMinVersion>\n"; + this->WriteElemEscapeXML("WindowsTargetPlatformMinVersion", + targetPlatformVersion, 2); } } // Added IoT Startup Task support if (this->GeneratorTarget->GetPropertyAsBool("VS_IOT_STARTUP_TASK")) { - this->WriteString("<ContainsStartupTask>true</ContainsStartupTask>\n", 2); + this->WriteElem("ContainsStartupTask", "true", 2); } } @@ -4150,7 +3983,7 @@ void cmVisualStudio10TargetGenerator::WriteMissingFilesWP80() ConvertToWindowsSlash(sourceFile); this->WriteString("<Xml Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(sourceFile) << "\">\n"; - this->WriteString("<SubType>Designer</SubType>\n", 3); + this->WriteElem("SubType", "Designer", 3); this->WriteString("</Xml>\n", 2); this->AddedFiles.push_back(sourceFile); @@ -4428,7 +4261,7 @@ void cmVisualStudio10TargetGenerator::WriteCommonMissingFiles( ConvertToWindowsSlash(sourceFile); this->WriteString("<AppxManifest Include=\"", 2); (*this->BuildFileStream) << cmVS10EscapeXML(sourceFile) << "\">\n"; - this->WriteString("<SubType>Designer</SubType>\n", 3); + this->WriteElem("SubType", "Designer", 3); this->WriteString("</AppxManifest>\n", 2); this->AddedFiles.push_back(sourceFile); diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 33d4fb7..d557255 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -53,8 +53,14 @@ private: std::vector<std::string> Configs; }; + struct Elem; + std::string ConvertPath(std::string const& path, bool forceRelative); void WriteString(const char* line, int indentLevel); + void WriteElem(const char* tag, const char* val, int indentLevel); + void WriteElem(const char* tag, std::string const& val, int indentLevel); + void WriteElemEscapeXML(const char* tag, std::string const& val, + int indentLevel); void WriteProjectConfigurations(); void WriteProjectConfigurationValues(); void WriteMSToolConfigurationValues(std::string const& config); @@ -62,9 +68,9 @@ private: void WriteHeaderSource(cmSourceFile const* sf); void WriteExtraSource(cmSourceFile const* sf); void WriteNsightTegraConfigurationValues(std::string const& config); - void WriteSource(std::string const& tool, cmSourceFile const* sf, - const char* end = 0); - void WriteExcludeFromBuild(std::vector<size_t> const& exclude_configs); + void WriteSource(std::string const& tool, cmSourceFile const* sf); + void WriteExcludeFromBuild(Elem&, + std::vector<size_t> const& exclude_configs); void WriteAllSources(); void WriteDotNetReferences(); void WriteDotNetReference(std::string const& ref, std::string const& hint); @@ -141,7 +147,7 @@ private: void WriteGroups(); void WriteProjectReferences(); void WriteApplicationTypeSettings(); - bool OutputSourceSpecificFlags(cmSourceFile const* source); + void OutputSourceSpecificFlags(Elem&, cmSourceFile const* source); void AddLibraries(cmComputeLinkInformation& cli, std::vector<std::string>& libVec, std::vector<std::string>& vsTargetVec); @@ -153,7 +159,7 @@ private: void WriteEvent(const char* name, std::vector<cmCustomCommand> const& commands, std::string const& configName); - void WriteGroupSources(const char* name, ToolSources const& sources, + void WriteGroupSources(std::string const& name, ToolSources const& sources, std::vector<cmSourceGroup>&); void AddMissingSourceGroups(std::set<cmSourceGroup*>& groupsUsed, const std::vector<cmSourceGroup>& allGroups); @@ -190,19 +196,19 @@ private: bool InSourceBuild; std::vector<std::string> Configurations; std::vector<TargetsFileAndConfigs> TargetsFileAndConfigsVec; - cmGeneratorTarget* GeneratorTarget; - cmMakefile* Makefile; - std::string Platform; - std::string GUID; - std::string Name; + cmGeneratorTarget* const GeneratorTarget; + cmMakefile* const Makefile; + std::string const Platform; + std::string const Name; + std::string const GUID; bool MSTools; bool Managed; bool NsightTegra; int NsightTegraVersion[4]; bool TargetCompileAsWinRT; - cmGlobalVisualStudio10Generator* GlobalGenerator; + cmGlobalVisualStudio10Generator* const GlobalGenerator; cmGeneratedFileStream* BuildFileStream; - cmLocalVisualStudio7Generator* LocalGenerator; + cmLocalVisualStudio7Generator* const LocalGenerator; std::set<cmSourceFile const*> SourcesVisited; std::set<std::string> CSharpCustomCommandNames; bool IsMissingFiles; diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index ccbff83..2095d23 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -152,9 +152,8 @@ bool cmVisualStudioGeneratorOptions::IsManaged() const bool cmVisualStudioGeneratorOptions::UsingUnicode() const { // Look for the a _UNICODE definition. - for (std::vector<std::string>::const_iterator di = this->Defines.begin(); - di != this->Defines.end(); ++di) { - if (*di == "_UNICODE") { + for (std::string const& di : this->Defines) { + if (di == "_UNICODE") { return true; } } @@ -163,9 +162,8 @@ bool cmVisualStudioGeneratorOptions::UsingUnicode() const bool cmVisualStudioGeneratorOptions::UsingSBCS() const { // Look for the a _SBCS definition. - for (std::vector<std::string>::const_iterator di = this->Defines.begin(); - di != this->Defines.end(); ++di) { - if (*di == "_SBCS") { + for (std::string const& di : this->Defines) { + if (di == "_SBCS") { return true; } } @@ -227,7 +225,7 @@ void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration() // It translates to -arch=<virtual> -code=<real>. cmSystemTools::ReplaceString(arch_name, "sm_", "compute_"); } - for (auto const& c : codes) { + for (std::string const& c : codes) { std::string entry = arch_name + "," + c; result.push_back(entry); } @@ -237,7 +235,7 @@ void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration() // -gencode=<arch>,<code> // -gencode=<arch>,[<code1>,<code2>] // -gencode=<arch>,"<code1>,<code2>" - for (auto const& e : gencode) { + for (std::string const& e : gencode) { std::string entry = e; cmSystemTools::ReplaceString(entry, "arch=", ""); cmSystemTools::ReplaceString(entry, "code=", ""); @@ -285,7 +283,7 @@ void cmVisualStudioGeneratorOptions::FixManifestUACFlags() uacExecuteLevelMap["highestAvailable"] = "HighestAvailable"; uacExecuteLevelMap["requireAdministrator"] = "RequireAdministrator"; - for (auto const& subopt : subOptions) { + for (std::string const& subopt : subOptions) { std::vector<std::string> keyValue; cmsys::SystemTools::Split(subopt, keyValue, '='); if (keyValue.size() != 2 || (uacMap.find(keyValue[0]) == uacMap.end())) { @@ -332,9 +330,8 @@ void cmVisualStudioGeneratorOptions::Parse(const char* flags) // Process flags that need to be represented specially in the IDE // project file. - for (std::vector<std::string>::iterator ai = args.begin(); ai != args.end(); - ++ai) { - this->HandleFlag(ai->c_str()); + for (std::string const& ai : args) { + this->HandleFlag(ai); } } @@ -396,23 +393,23 @@ void cmVisualStudioGeneratorOptions::Reparse(std::string const& key) this->Parse(original.c_str()); } -void cmVisualStudioGeneratorOptions::StoreUnknownFlag(const char* flag) +void cmVisualStudioGeneratorOptions::StoreUnknownFlag(std::string const& flag) { // Look for Intel Fortran flags that do not map well in the flag table. if (this->CurrentTool == FortranCompiler) { - if (strcmp(flag, "/dbglibs") == 0) { + if (flag == "/dbglibs") { this->FortranRuntimeDebug = true; return; } - if (strcmp(flag, "/threads") == 0) { + if (flag == "/threads") { this->FortranRuntimeMT = true; return; } - if (strcmp(flag, "/libs:dll") == 0) { + if (flag == "/libs:dll") { this->FortranRuntimeDLL = true; return; } - if (strcmp(flag, "/libs:static") == 0) { + if (flag == "/libs:static") { this->FortranRuntimeDLL = false; return; } @@ -420,7 +417,7 @@ void cmVisualStudioGeneratorOptions::StoreUnknownFlag(const char* flag) // This option is not known. Store it in the output flags. std::string const opts = cmOutputConverter::EscapeWindowsShellArgument( - flag, cmOutputConverter::Shell_Flag_AllowMakeVariables | + flag.c_str(), cmOutputConverter::Shell_Flag_AllowMakeVariables | cmOutputConverter::Shell_Flag_VSIDE); this->AppendFlagString(this->UnknownFlagField, opts); } @@ -437,7 +434,8 @@ cmIDEOptions::FlagValue cmVisualStudioGeneratorOptions::TakeFlag( return value; } -void cmVisualStudioGeneratorOptions::SetConfiguration(const char* config) +void cmVisualStudioGeneratorOptions::SetConfiguration( + const std::string& config) { this->Configuration = config; } @@ -566,31 +564,27 @@ void cmVisualStudioGeneratorOptions::OutputFlagMap(std::ostream& fout, const char* indent) { if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { - for (std::map<std::string, FlagValue>::iterator m = this->FlagMap.begin(); - m != this->FlagMap.end(); ++m) { + for (auto const& m : this->FlagMap) { fout << indent; if (!this->Configuration.empty()) { this->TargetGenerator->WritePlatformConfigTag( - m->first.c_str(), this->Configuration.c_str(), 0, 0, 0, &fout); + m.first.c_str(), this->Configuration.c_str(), 0, 0, 0, &fout); } else { - fout << "<" << m->first << ">"; + fout << "<" << m.first << ">"; } const char* sep = ""; - for (std::vector<std::string>::iterator i = m->second.begin(); - i != m->second.end(); ++i) { - fout << sep << cmVisualStudio10GeneratorOptionsEscapeForXML(*i); + for (std::string const& i : m.second) { + fout << sep << cmVisualStudio10GeneratorOptionsEscapeForXML(i); sep = ";"; } - fout << "</" << m->first << ">\n"; + fout << "</" << m.first << ">\n"; } } else { - for (std::map<std::string, FlagValue>::iterator m = this->FlagMap.begin(); - m != this->FlagMap.end(); ++m) { - fout << indent << m->first << "=\""; + for (auto const& m : this->FlagMap) { + fout << indent << m.first << "=\""; const char* sep = ""; - for (std::vector<std::string>::iterator i = m->second.begin(); - i != m->second.end(); ++i) { - fout << sep << cmVisualStudioGeneratorOptionsEscapeForXML(*i); + for (std::string const& i : m.second) { + fout << sep << cmVisualStudioGeneratorOptionsEscapeForXML(i); sep = ";"; } fout << "\"\n"; diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index 2dffe9b..5c3e415 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -91,7 +91,7 @@ public: const char* suffix, const std::string& lang); void OutputFlagMap(std::ostream& fout, const char* indent); - void SetConfiguration(const char* config); + void SetConfiguration(const std::string& config); private: cmLocalVisualStudioGenerator* LocalGenerator; @@ -107,7 +107,7 @@ private: std::string UnknownFlagField; - virtual void StoreUnknownFlag(const char* flag); + void StoreUnknownFlag(std::string const& flag) override; FlagValue TakeFlag(std::string const& key); }; diff --git a/Source/cmWorkingDirectory.cxx b/Source/cmWorkingDirectory.cxx index 99c9ba8..816f104 100644 --- a/Source/cmWorkingDirectory.cxx +++ b/Source/cmWorkingDirectory.cxx @@ -4,10 +4,12 @@ #include "cmSystemTools.h" +#include <cerrno> + cmWorkingDirectory::cmWorkingDirectory(std::string const& newdir) { this->OldDir = cmSystemTools::GetCurrentWorkingDirectory(); - cmSystemTools::ChangeDirectory(newdir); + this->SetDirectory(newdir); } cmWorkingDirectory::~cmWorkingDirectory() @@ -15,10 +17,20 @@ cmWorkingDirectory::~cmWorkingDirectory() this->Pop(); } +bool cmWorkingDirectory::SetDirectory(std::string const& newdir) +{ + if (cmSystemTools::ChangeDirectory(newdir) == 0) { + this->ResultCode = 0; + return true; + } + this->ResultCode = errno; + return false; +} + void cmWorkingDirectory::Pop() { if (!this->OldDir.empty()) { - cmSystemTools::ChangeDirectory(this->OldDir); + this->SetDirectory(this->OldDir); this->OldDir.clear(); } } diff --git a/Source/cmWorkingDirectory.h b/Source/cmWorkingDirectory.h index aff9267..1f18ce7 100644 --- a/Source/cmWorkingDirectory.h +++ b/Source/cmWorkingDirectory.h @@ -9,6 +9,12 @@ /** \class cmWorkingDirectory * \brief An RAII class to manipulate the working directory. + * + * The current working directory is set to the location given to the + * constructor. The working directory can be changed again as needed + * by calling SetDirectory(). When the object is destroyed, the destructor + * will restore the working directory to what it was when the object was + * created, regardless of any calls to SetDirectory() in the meantime. */ class cmWorkingDirectory { @@ -16,10 +22,21 @@ public: cmWorkingDirectory(std::string const& newdir); ~cmWorkingDirectory(); + bool SetDirectory(std::string const& newdir); void Pop(); + bool Failed() const { return ResultCode != 0; } + + /** \return 0 if the last attempt to set the working directory was + * successful. If it failed, the value returned will be the + * \c errno value associated with the failure. A description + * of the error code can be obtained by passing the result + * to \c std::strerror(). + */ + int GetLastResult() const { return ResultCode; } private: std::string OldDir; + int ResultCode; }; #endif diff --git a/Source/cmXMLWriter.h b/Source/cmXMLWriter.h index 7bae21e..80940ee 100644 --- a/Source/cmXMLWriter.h +++ b/Source/cmXMLWriter.h @@ -133,4 +133,56 @@ private: bool IsContent; }; +class cmXMLElement; // IWYU pragma: keep + +class cmXMLDocument +{ +public: + cmXMLDocument(cmXMLWriter& xml) + : xmlwr(xml) + { + xmlwr.StartDocument(); + } + ~cmXMLDocument() { xmlwr.EndDocument(); } +private: + friend class cmXMLElement; + cmXMLWriter& xmlwr; +}; + +class cmXMLElement +{ +public: + cmXMLElement(cmXMLWriter& xml, const char* tag) + : xmlwr(xml) + { + xmlwr.StartElement(tag); + } + cmXMLElement(cmXMLElement& par, const char* tag) + : xmlwr(par.xmlwr) + { + xmlwr.StartElement(tag); + } + cmXMLElement(cmXMLDocument& doc, const char* tag) + : xmlwr(doc.xmlwr) + { + xmlwr.StartElement(tag); + } + ~cmXMLElement() { xmlwr.EndElement(); } + + template <typename T> + cmXMLElement& Attribute(const char* name, T const& value) + { + xmlwr.Attribute(name, value); + return *this; + } + template <typename T> + void Content(T const& content) + { + xmlwr.Content(content); + } + +private: + cmXMLWriter& xmlwr; +}; + #endif diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 5620723..323bcf6 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -98,13 +98,13 @@ #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" #include <algorithm> +#include <cstring> #include <iostream> #include <iterator> #include <memory> // IWYU pragma: keep #include <sstream> #include <stdio.h> #include <stdlib.h> -#include <string.h> #include <utility> namespace { @@ -2209,6 +2209,15 @@ int cmake::GetSystemInformation(std::vector<std::string>& args) { // now run cmake on the CMakeLists file cmWorkingDirectory workdir(destPath); + if (workdir.Failed()) { + // We created the directory and we were able to copy the CMakeLists.txt + // file to it, so we wouldn't expect to get here unless the default + // permissions are questionable or some other process has deleted the + // directory + std::cerr << "Failed to change to directory " << destPath << " : " + << std::strerror(workdir.GetLastResult()) << std::endl; + return 1; + } std::vector<std::string> args2; args2.push_back(args[0]); args2.push_back(destPath); @@ -2387,17 +2396,17 @@ int cmake::Build(const std::string& dir, const std::string& target, std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n"; return 1; } - std::unique_ptr<cmGlobalGenerator> gen( - this->CreateGlobalGenerator(cachedGenerator)); - if (!gen.get()) { + cmGlobalGenerator* gen = this->CreateGlobalGenerator(cachedGenerator); + if (!gen) { std::cerr << "Error: could create CMAKE_GENERATOR \"" << cachedGenerator << "\"\n"; return 1; } + this->SetGlobalGenerator(gen); const char* cachedGeneratorInstance = this->State->GetCacheEntryValue("CMAKE_GENERATOR_INSTANCE"); if (cachedGeneratorInstance) { - cmMakefile mf(gen.get(), this->GetCurrentSnapshot()); + cmMakefile mf(gen, this->GetCurrentSnapshot()); if (!gen->SetGeneratorInstance(cachedGeneratorInstance, &mf)) { return 1; } diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 0988c3c..6f3a90f 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -359,7 +359,8 @@ struct CoCompileJob int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args) { std::vector<CoCompileJob> jobs; - std::string sourceFile; // store --source= + std::string sourceFile; // store --source= + std::vector<std::string> launchers; // store --launcher= // Default is to run the original command found after -- if the option // does not need to do that, it should be specified here, currently only @@ -390,15 +391,17 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args) } } } - if (cmHasLiteralPrefix(arg, "--source=")) { - sourceFile = arg.substr(9); - optionFound = true; - } - // if it was not a co-compiler or --source then error if (!optionFound) { - std::cerr << "__run_co_compile given unknown argument: " << arg - << "\n"; - return 1; + if (cmHasLiteralPrefix(arg, "--source=")) { + sourceFile = arg.substr(9); + } else if (cmHasLiteralPrefix(arg, "--launcher=")) { + cmSystemTools::ExpandListArgument(arg.substr(11), launchers, true); + } else { + // if it was not a co-compiler or --source/--launcher then error + std::cerr << "__run_co_compile given unknown argument: " << arg + << "\n"; + return 1; + } } } else { // if not doing_options then push to orig_cmd orig_cmd.push_back(arg); @@ -436,6 +439,11 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args) return 0; } + // Prepend launcher argument(s), if any + if (!launchers.empty()) { + orig_cmd.insert(orig_cmd.begin(), launchers.begin(), launchers.end()); + } + // Now run the real compiler command and return its result value int ret; if (!cmSystemTools::RunSingleCommand(orig_cmd, nullptr, nullptr, &ret, @@ -689,8 +697,6 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) // Touch file if (args[1] == "touch_nocreate" && args.size() > 2) { for (std::string::size_type cc = 2; cc < args.size(); cc++) { - // Complain if the file could not be removed, still exists, - // and the -f option was not given. if (!cmSystemTools::Touch(args[cc], false)) { return 1; } diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt index 06df53f..126076d 100644 --- a/Tests/CMakeLib/CMakeLists.txt +++ b/Tests/CMakeLib/CMakeLists.txt @@ -49,3 +49,6 @@ if(TEST_CompileCommandOutput) endif() add_subdirectory(PseudoMemcheck) + +add_executable(testAffinity testAffinity.cxx) +target_link_libraries(testAffinity CMakeLib) diff --git a/Tests/CMakeLib/testAffinity.cxx b/Tests/CMakeLib/testAffinity.cxx new file mode 100644 index 0000000..4b82280 --- /dev/null +++ b/Tests/CMakeLib/testAffinity.cxx @@ -0,0 +1,18 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmAffinity.h" + +#include <cstddef> +#include <iostream> +#include <set> + +int main() +{ + std::set<size_t> cpus = cmAffinity::GetProcessorsAvailable(); + if (!cpus.empty()) { + std::cout << "CPU affinity mask count is '" << cpus.size() << "'.\n"; + } else { + std::cout << "CPU affinity not supported on this platform.\n"; + } + return 0; +} diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 08bfebe..101502f 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -348,6 +348,7 @@ if(BUILD_TESTING) if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^89]|[89][0-9])") ADD_TEST_MACRO(CSharpOnly CSharpOnly) ADD_TEST_MACRO(CSharpLinkToCxx CSharpLinkToCxx) + ADD_TEST_MACRO(CSharpLinkFromCxx CSharpLinkFromCxx) endif() ADD_TEST_MACRO(COnly COnly) @@ -816,6 +817,8 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release ADD_TEST_MACRO(CustomCommandByproducts CustomCommandByproducts) + ADD_TEST_MACRO(CommandLength CommandLength) + ADD_TEST_MACRO(EmptyDepends ${CMAKE_CTEST_COMMAND}) add_test(CustomCommandWorkingDirectory ${CMAKE_CTEST_COMMAND} @@ -1323,6 +1326,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release add_subdirectory(FindBZip2) endif() + if(CMake_TEST_FindCURL) + add_subdirectory(FindCURL) + endif() + if(CMake_TEST_FindDoxygen) add_subdirectory(FindDoxygen) endif() @@ -1364,6 +1371,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release add_subdirectory(FindLibUV) endif() + if(CMake_TEST_FindLibXml2) + add_subdirectory(FindLibXml2) + endif() + if(CMake_TEST_FindLTTngUST) add_subdirectory(FindLTTngUST) endif() @@ -1443,6 +1454,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release ) list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProject") set_tests_properties(ExternalProject PROPERTIES + RUN_SERIAL 1 TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT}) add_test(NAME ExternalProjectSubdir @@ -1482,6 +1494,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release ) list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectLocal") set_tests_properties(ExternalProjectLocal PROPERTIES + RUN_SERIAL 1 TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT}) add_test(ExternalProjectUpdateSetup ${CMAKE_CTEST_COMMAND} @@ -1497,6 +1510,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release ) list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectUpdate") set_tests_properties(ExternalProjectUpdateSetup PROPERTIES + RUN_SERIAL 1 TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT}) add_test(NAME ExternalProjectUpdate @@ -1511,6 +1525,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release ) list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectUpdate") set_tests_properties(ExternalProjectUpdate PROPERTIES + RUN_SERIAL 1 TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT} WORKING_DIRECTORY ${CMake_SOURCE_DIR}/Tests/ExternalProjectUpdate DEPENDS ExternalProjectUpdateSetup ) diff --git a/Tests/CSharpLinkFromCxx/.gitattributes b/Tests/CSharpLinkFromCxx/.gitattributes new file mode 100644 index 0000000..57a39049 --- /dev/null +++ b/Tests/CSharpLinkFromCxx/.gitattributes @@ -0,0 +1 @@ +UsefulManagedCppClass.* -format.clang-format diff --git a/Tests/CSharpLinkFromCxx/CMakeLists.txt b/Tests/CSharpLinkFromCxx/CMakeLists.txt new file mode 100644 index 0000000..9a1a993 --- /dev/null +++ b/Tests/CSharpLinkFromCxx/CMakeLists.txt @@ -0,0 +1,19 @@ +# Take a C# shared library and link it to a managed C++ shared library +cmake_minimum_required(VERSION 3.10) +project (CSharpLinkFromCxx CXX CSharp) + +add_library(CSharpLibrary SHARED UsefulCSharpClass.cs) + +# we have to change the default flags for the +# managed C++ project to build +string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) +string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) + +# The C# project is a dependency of the C++/CLI project +add_library(ManagedCppLibrary SHARED UsefulManagedCppClass.cpp UsefulManagedCppClass.hpp) +target_compile_options(ManagedCppLibrary PRIVATE "/clr") +target_link_libraries(ManagedCppLibrary PUBLIC CSharpLibrary) + +# Main executable for the test framework +add_executable(CSharpLinkFromCxx CSharpLinkFromCxx.cs) +target_link_libraries(CSharpLinkFromCxx PRIVATE ManagedCppLibrary) diff --git a/Tests/CSharpLinkFromCxx/CSharpLinkFromCxx.cs b/Tests/CSharpLinkFromCxx/CSharpLinkFromCxx.cs new file mode 100644 index 0000000..31a74eb --- /dev/null +++ b/Tests/CSharpLinkFromCxx/CSharpLinkFromCxx.cs @@ -0,0 +1,16 @@ +using System; +using CSharpLibrary; + +namespace CSharpLinkFromCxx +{ + internal class CSharpLinkFromCxx + { + public static void Main(string[] args) + { + Console.WriteLine("Starting test for CSharpLinkFromCxx"); + + var useful = new UsefulManagedCppClass(); + useful.RunTest(); + } + } +} diff --git a/Tests/CSharpLinkFromCxx/UsefulCSharpClass.cs b/Tests/CSharpLinkFromCxx/UsefulCSharpClass.cs new file mode 100644 index 0000000..749e57d --- /dev/null +++ b/Tests/CSharpLinkFromCxx/UsefulCSharpClass.cs @@ -0,0 +1,12 @@ +using System; + +namespace CSharpLibrary +{ + public class UsefulCSharpClass + { + public string GetSomethingUseful() + { + return "Something Useful"; + } + } +} diff --git a/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.cpp b/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.cpp new file mode 100644 index 0000000..9468812 --- /dev/null +++ b/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.cpp @@ -0,0 +1,15 @@ +#include "UsefulManagedCppClass.hpp" + +namespace CSharpLibrary +{ + UsefulManagedCppClass::UsefulManagedCppClass() + { + auto useful = gcnew UsefulCSharpClass(); + m_usefulString = useful->GetSomethingUseful(); + } + + void UsefulManagedCppClass::RunTest() + { + Console::WriteLine("Printing from Managed CPP Class: " + m_usefulString); + } +} diff --git a/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.hpp b/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.hpp new file mode 100644 index 0000000..def7cea --- /dev/null +++ b/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.hpp @@ -0,0 +1,16 @@ +using namespace System; + +namespace CSharpLibrary +{ + public ref class UsefulManagedCppClass + { + public: + + UsefulManagedCppClass(); + void RunTest(); + + private: + + String^ m_usefulString; + }; +} diff --git a/Tests/CTestTest/test.cmake.in b/Tests/CTestTest/test.cmake.in index 589bd44..23166a7 100644 --- a/Tests/CTestTest/test.cmake.in +++ b/Tests/CTestTest/test.cmake.in @@ -62,7 +62,7 @@ COVERAGE_COMMAND:FILEPATH=@COVERAGE_COMMAND@ set (CTEST_DASHBOARD_ROOT "@CMAKE_CURRENT_BINARY_DIR@/Tests/CTestTest") -# set any extra environment varibles here +# set any extra environment variables here set (CTEST_ENVIRONMENT ) diff --git a/Tests/CommandLength/CMakeLists.txt b/Tests/CommandLength/CMakeLists.txt new file mode 100644 index 0000000..6836051 --- /dev/null +++ b/Tests/CommandLength/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.10) +project(CommandLength C) + +add_executable(CommandLength test.c) +add_custom_command(TARGET CommandLength POST_BUILD VERBATIM + COMMAND ${CMAKE_COMMAND} -E make_directory log) + +set(msg "xxxx $$$$ yyyy") +set(msg "${msg} ${msg}") +set(msg "${msg} ${msg}") +set(msg "${msg} ${msg}") +set(msg "${msg} ${msg}") +foreach(i RANGE 1 1000) + add_custom_command(TARGET CommandLength POST_BUILD VERBATIM + COMMAND ${CMAKE_COMMAND} -E echo "${i} ${msg}" > log/${i} + ) +endforeach() diff --git a/Tests/CommandLength/test.c b/Tests/CommandLength/test.c new file mode 100644 index 0000000..f8b643a --- /dev/null +++ b/Tests/CommandLength/test.c @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} diff --git a/Tests/CompileOptions/CMakeLists.txt b/Tests/CompileOptions/CMakeLists.txt index 692e0de..c9f1710 100644 --- a/Tests/CompileOptions/CMakeLists.txt +++ b/Tests/CompileOptions/CMakeLists.txt @@ -18,9 +18,21 @@ set_property(TARGET CompileOptions PROPERTY COMPILE_OPTIONS "-DTEST_DEFINE" "-DNEEDS_ESCAPE=\"E$CAPE\"" "$<$<CXX_COMPILER_ID:GNU>:-DTEST_DEFINE_GNU>" + "SHELL:" # produces no options ${c_tests} ${cxx_tests} ) +if(BORLAND OR WATCOM) + # these compilers do not support separate -D flags + target_compile_definitions(CompileOptions PRIVATE NO_DEF_TESTS) +else() + set_property(TARGET CompileOptions APPEND PROPERTY COMPILE_OPTIONS + "SHELL:-D DEF_A" + "$<1:SHELL:-D DEF_B>" + "SHELL:-D 'DEF_C' -D \"DEF_D\"" + [[SHELL:-D "DEF_STR=\"string with spaces\""]] + ) +endif() if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|Borland|Embarcadero") set_property(TARGET CompileOptions APPEND PROPERTY COMPILE_OPTIONS diff --git a/Tests/CompileOptions/main.cpp b/Tests/CompileOptions/main.cpp index 63a0480..4779b88 100644 --- a/Tests/CompileOptions/main.cpp +++ b/Tests/CompileOptions/main.cpp @@ -12,6 +12,28 @@ #endif #endif +#ifndef NO_DEF_TESTS +#ifndef DEF_A +#error Expected definition DEF_A +#endif + +#ifndef DEF_B +#error Expected definition DEF_B +#endif + +#ifndef DEF_C +#error Expected definition DEF_C +#endif + +#ifndef DEF_D +#error Expected definition DEF_D +#endif + +#ifndef DEF_STR +#error Expected definition DEF_STR +#endif +#endif + #include <string.h> int main() @@ -20,6 +42,9 @@ int main() #ifdef TEST_OCTOTHORPE && strcmp(TEST_OCTOTHORPE, "#") == 0 #endif +#ifndef NO_DEF_TESTS + && strcmp(DEF_STR, "string with spaces") == 0 +#endif && strcmp(EXPECTED_C_COMPILER_VERSION, TEST_C_COMPILER_VERSION) == 0 && strcmp(EXPECTED_CXX_COMPILER_VERSION, TEST_CXX_COMPILER_VERSION) == diff --git a/Tests/Complex/Cache/CMakeCache.txt b/Tests/Complex/Cache/CMakeCache.txt index 17c55aa..727faa2 100644 --- a/Tests/Complex/Cache/CMakeCache.txt +++ b/Tests/Complex/Cache/CMakeCache.txt @@ -5,7 +5,7 @@ # If you do want to change a value, simply edit, save, and exit the editor. # The syntax for the file is as follows: # KEY:TYPE=VALUE -# KEY is the name of a varible in the cache. +# KEY is the name of a variable in the cache. # TYPE is a hint to GUI's for the type of VALUE, DO NOT EDIT TYPE!. # VALUE is the current value for the KEY. diff --git a/Tests/ComplexOneConfig/Cache/CMakeCache.txt b/Tests/ComplexOneConfig/Cache/CMakeCache.txt index 17c55aa..727faa2 100644 --- a/Tests/ComplexOneConfig/Cache/CMakeCache.txt +++ b/Tests/ComplexOneConfig/Cache/CMakeCache.txt @@ -5,7 +5,7 @@ # If you do want to change a value, simply edit, save, and exit the editor. # The syntax for the file is as follows: # KEY:TYPE=VALUE -# KEY is the name of a varible in the cache. +# KEY is the name of a variable in the cache. # TYPE is a hint to GUI's for the type of VALUE, DO NOT EDIT TYPE!. # VALUE is the current value for the KEY. diff --git a/Tests/Contracts/PLplot/CMakeLists.txt b/Tests/Contracts/PLplot/CMakeLists.txt index b87b4c3..7051d62 100644 --- a/Tests/Contracts/PLplot/CMakeLists.txt +++ b/Tests/Contracts/PLplot/CMakeLists.txt @@ -9,7 +9,7 @@ if(NOT PLplot_GIT_TAG) set(PLplot_GIT_TAG "plplot-5.13.0") endif() ExternalProject_Add(PLplot - GIT_REPOSITORY "https://git.code.sf.net/p/plplot/plplot.git" + GIT_REPOSITORY "git://git.code.sf.net/p/plplot/plplot" GIT_TAG "${PLplot_GIT_TAG}" PREFIX "${PLplot_PREFIX}" CMAKE_ARGS diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index eeae3f0..0f1a556 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -83,11 +83,23 @@ set_property(TARGET testLib7 PROPERTY OUTPUT_NAME testLib7-$<CONFIG>) add_library(testLib8 OBJECT testLib8A.c testLib8B.c sub/testLib8C.c) if(NOT CMAKE_GENERATOR STREQUAL "Xcode" OR NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;$]") - set(maybe_testLib8 testLib8) + set(maybe_OBJECTS_DESTINATION OBJECTS DESTINATION $<1:lib>) else() - set(maybe_testLib8 "") + set(maybe_OBJECTS_DESTINATION "") endif() +cmake_policy(PUSH) +cmake_policy(SET CMP0022 NEW) +add_library(testLib9ObjPub OBJECT testLib9ObjPub.c) +target_compile_definitions(testLib9ObjPub INTERFACE testLib9ObjPub_USED) +add_library(testLib9ObjPriv OBJECT testLib9ObjPriv.c) +target_compile_definitions(testLib9ObjPriv INTERFACE testLib9ObjPriv_USED) +add_library(testLib9ObjIface OBJECT testLib9ObjIface.c) +target_compile_definitions(testLib9ObjIface INTERFACE testLib9ObjIface_USED) +add_library(testLib9 STATIC testLib9.c) +target_link_libraries(testLib9 INTERFACE testLib9ObjIface PUBLIC testLib9ObjPub PRIVATE testLib9ObjPriv) +cmake_policy(POP) + # Test using the target_link_libraries command to set the # LINK_INTERFACE_LIBRARIES* properties. We construct two libraries # providing the same two symbols. In each library one of the symbols @@ -344,6 +356,14 @@ install(FILES set_property(TARGET testLib2 APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS USING_TESTLIB2) set_property(TARGET testLib3 APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS USING_TESTLIB3) +set_target_properties(testLib3 PROPERTIES + EXPORT_PROPERTIES "EXPORTED_PROPERTY1" + EXPORTED_PROPERTY1 "EXPORTING_TESTLIB3") +set_target_properties(testLib4 PROPERTIES + EXPORTED_PROPERTY2 "EXPORTING_TESTLIB4_1" + EXPORTED_PROPERTY3 "EXPORTING_TESTLIB4_2") +set_property(TARGET testLib4 PROPERTY + EXPORT_PROPERTIES EXPORTED_PROPERTY2 EXPORTED_PROPERTY3) set_property(TARGET cmp0022NEW APPEND PROPERTY INTERFACE_LINK_LIBRARIES testLib2) # set_property(TARGET cmp0022NEW APPEND PROPERTY LINK_INTERFACE_LIBRARIES testLibIncludeRequired2) # TODO: Test for error @@ -483,7 +503,8 @@ install( TARGETS testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3 testExe4 testExe2lib testLib4lib testLib4libdbg testLib4libopt - testLib6 testLib7 ${maybe_testLib8} + testLib6 testLib7 testLib8 + testLib9 testLibCycleA testLibCycleB testLibNoSONAME cmp0022NEW cmp0022OLD @@ -492,10 +513,15 @@ install( RUNTIME DESTINATION $<1:bin> LIBRARY DESTINATION $<1:lib> NAMELINK_SKIP ARCHIVE DESTINATION $<1:lib> - OBJECTS DESTINATION $<1:lib> + ${maybe_OBJECTS_DESTINATION} FRAMEWORK DESTINATION Frameworks BUNDLE DESTINATION Applications ) +install( + TARGETS + testLib9ObjPub testLib9ObjPriv testLib9ObjIface + EXPORT exp + ) if (APPLE) file(COPY testLib4.h DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/testLib4.framework/Headers) file(COPY testLib4.h DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Debug/testLib4.framework/Headers) @@ -545,7 +571,8 @@ export(TARGETS testExe1 testLib1 testLib2 testLib3 FILE ExportBuildTree.cmake ) export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe4 testExe2lib - ${maybe_testLib8} + testLib8 + testLib9 testLib9ObjPub testLib9ObjPriv testLib9ObjIface testLib4lib testLib4libdbg testLib4libopt testLibCycleA testLibCycleB testLibNoSONAME diff --git a/Tests/ExportImport/Export/testLib9.c b/Tests/ExportImport/Export/testLib9.c new file mode 100644 index 0000000..fe8610b --- /dev/null +++ b/Tests/ExportImport/Export/testLib9.c @@ -0,0 +1,15 @@ +#ifndef testLib9ObjPub_USED +#error "testLib9ObjPub_USED not defined!" +#endif +#ifndef testLib9ObjPriv_USED +#error "testLib9ObjPriv_USED not defined!" +#endif +#ifdef testLib9ObjIface_USED +#error "testLib9ObjIface_USED defined but should not be!" +#endif +int testLib9ObjPub(void); +int testLib9ObjPriv(void); +int testLib9(void) +{ + return (testLib9ObjPub() + testLib9ObjPriv()); +} diff --git a/Tests/ExportImport/Export/testLib9ObjIface.c b/Tests/ExportImport/Export/testLib9ObjIface.c new file mode 100644 index 0000000..e75440a --- /dev/null +++ b/Tests/ExportImport/Export/testLib9ObjIface.c @@ -0,0 +1,11 @@ +/* Duplicate symbols from other sources to verify that this source + is not included when the object library is used. */ +int testLib9ObjMissing(void); +int testLib9ObjPub(void) +{ + return testLib9ObjMissing(); +} +int testLib9ObjPriv(void) +{ + return testLib9ObjMissing(); +} diff --git a/Tests/ExportImport/Export/testLib9ObjPriv.c b/Tests/ExportImport/Export/testLib9ObjPriv.c new file mode 100644 index 0000000..6fa63cc --- /dev/null +++ b/Tests/ExportImport/Export/testLib9ObjPriv.c @@ -0,0 +1,4 @@ +int testLib9ObjPriv(void) +{ + return 0; +} diff --git a/Tests/ExportImport/Export/testLib9ObjPub.c b/Tests/ExportImport/Export/testLib9ObjPub.c new file mode 100644 index 0000000..66e2624 --- /dev/null +++ b/Tests/ExportImport/Export/testLib9ObjPub.c @@ -0,0 +1,4 @@ +int testLib9ObjPub(void) +{ + return 0; +} diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt index 01960ea..39a89dc 100644 --- a/Tests/ExportImport/Import/A/CMakeLists.txt +++ b/Tests/ExportImport/Import/A/CMakeLists.txt @@ -32,6 +32,20 @@ add_executable(imp_testExe1 ${Import_BINARY_DIR}/exp_generated4.c ) +function(checkForProperty _TARGET _PROP _EXPECTED) + get_target_property(EXPORTED_PROPERTY ${_TARGET} "${_PROP}") + if (NOT EXPORTED_PROPERTY STREQUAL "${_EXPECTED}") + message(SEND_ERROR "${_TARGET} was expected to export \"${_PROP}\" with value \"${_EXPECTED}\" but got \"${EXPORTED_PROPERTY}\"") + endif() +endfunction() + +checkForProperty(bld_testLib3 "EXPORTED_PROPERTY1" "EXPORTING_TESTLIB3") +checkForProperty(exp_testLib3 "EXPORTED_PROPERTY1" "EXPORTING_TESTLIB3") +checkForProperty(bld_testLib4 "EXPORTED_PROPERTY2" "EXPORTING_TESTLIB4_1") +checkForProperty(exp_testLib4 "EXPORTED_PROPERTY2" "EXPORTING_TESTLIB4_1") +checkForProperty(bld_testLib4 "EXPORTED_PROPERTY3" "EXPORTING_TESTLIB4_2") +checkForProperty(exp_testLib4 "EXPORTED_PROPERTY3" "EXPORTING_TESTLIB4_2") + # Try linking to a library imported from the install tree. target_link_libraries(imp_testExe1 exp_testLib2 @@ -229,15 +243,44 @@ add_library(imp_lib1b STATIC imp_lib1.c) target_link_libraries(imp_lib1b bld_testLib2) if(NOT CMAKE_GENERATOR STREQUAL "Xcode" OR NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;$]") - # Create a executable that is using objects imported from the install tree - add_executable(imp_testLib8 imp_testLib8.c $<TARGET_OBJECTS:exp_testLib8>) + set(bld_objlib_type OBJECT_LIBRARY) + + # Create executables using objects imported from the install tree + add_executable(imp_testLib8_src imp_testLib8.c $<TARGET_OBJECTS:exp_testLib8>) + add_executable(imp_testLib8_link imp_testLib8.c) + target_link_libraries(imp_testLib8_link exp_testLib8) if(NOT CMAKE_GENERATOR STREQUAL "Xcode" OR NOT XCODE_VERSION VERSION_LESS 5) - # Create a executable that is using objects imported from the build tree - add_executable(imp_testLib8b imp_testLib8.c $<TARGET_OBJECTS:bld_testLib8>) + # Create executables using objects imported from the build tree + add_executable(imp_testLib8b_src imp_testLib8.c $<TARGET_OBJECTS:bld_testLib8>) + add_executable(imp_testLib8b_link imp_testLib8.c) + target_link_libraries(imp_testLib8b_link bld_testLib8) endif() +else() + set(bld_objlib_type INTERFACE_LIBRARY) endif() +# Create an executable that uses a library imported from the install tree +# that itself was built using an object library. Verify we get the usage +# requirements. +add_executable(imp_testLib9 imp_testLib9.c) +target_link_libraries(imp_testLib9 exp_testLib9) +# Similarly for importing from the build tree. +add_executable(imp_testLib9b imp_testLib9.c) +target_link_libraries(imp_testLib9b bld_testLib9) + +# Check that object libraries were transformed on export as expected. +foreach(vis Pub Priv Iface) + get_property(type TARGET exp_testLib9Obj${vis} PROPERTY TYPE) + if(NOT type STREQUAL INTERFACE_LIBRARY) + message(FATAL_ERROR "exp_testLib9Obj${vis} type is '${type}', not 'INTERFACE_LIBRARY'") + endif() + get_property(type TARGET bld_testLib9Obj${vis} PROPERTY TYPE) + if(NOT type STREQUAL "${bld_objlib_type}") + message(FATAL_ERROR "bld_testLib9Obj${vis} type is '${type}', not '${bld_objlib_type}'") + endif() +endforeach() + #----------------------------------------------------------------------------- # Test that handling imported targets, including transitive dependencies, # works in CheckFunctionExists (...and hopefully all other try_compile() checks diff --git a/Tests/ExportImport/Import/A/imp_testLib9.c b/Tests/ExportImport/Import/A/imp_testLib9.c new file mode 100644 index 0000000..f9c05fd --- /dev/null +++ b/Tests/ExportImport/Import/A/imp_testLib9.c @@ -0,0 +1,16 @@ +#ifndef testLib9ObjPub_USED +#error "testLib9ObjPub_USED not defined!" +#endif +#ifdef testLib9ObjPriv_USED +#error "testLib9ObjPriv_USED defined but should not be!" +#endif +#ifndef testLib9ObjIface_USED +#error "testLib9ObjIface_USED not defined!" +#endif + +int testLib9(void); + +int main() +{ + return testLib9(); +} diff --git a/Tests/FindCURL/CMakeLists.txt b/Tests/FindCURL/CMakeLists.txt new file mode 100644 index 0000000..0cfd629 --- /dev/null +++ b/Tests/FindCURL/CMakeLists.txt @@ -0,0 +1,10 @@ +add_test(NAME FindCURL.Test COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindCURL/Test" + "${CMake_BINARY_DIR}/Tests/FindCURL/Test" + ${build_generator_args} + --build-project TestFindCURL + --build-options ${build_options} + --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> + ) diff --git a/Tests/FindCURL/Test/CMakeLists.txt b/Tests/FindCURL/Test/CMakeLists.txt new file mode 100644 index 0000000..f0e5568 --- /dev/null +++ b/Tests/FindCURL/Test/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.10) +project(TestFindCURL C) +include(CTest) + +find_package(CURL REQUIRED) + +add_definitions(-DCMAKE_EXPECTED_CURL_VERSION="${CURL_VERSION_STRING}") + +add_executable(test_tgt main.c) +target_link_libraries(test_tgt CURL::CURL) +add_test(NAME test_tgt COMMAND test_tgt) + +add_executable(test_var main.c) +target_include_directories(test_var PRIVATE ${CURL_INCLUDE_DIRS}) +target_link_libraries(test_var PRIVATE ${CURL_LIBRARIES}) +add_test(NAME test_var COMMAND test_var) diff --git a/Tests/FindCURL/Test/main.c b/Tests/FindCURL/Test/main.c new file mode 100644 index 0000000..263775f --- /dev/null +++ b/Tests/FindCURL/Test/main.c @@ -0,0 +1,17 @@ +#include <curl/curl.h> +#include <stdio.h> +#include <stdlib.h> + +int main() +{ + struct curl_slist* slist; + + curl_global_init(0); + + slist = curl_slist_append(NULL, "CMake"); + curl_slist_free_all(slist); + + curl_global_cleanup(); + + return 0; +} diff --git a/Tests/FindLibXml2/CMakeLists.txt b/Tests/FindLibXml2/CMakeLists.txt new file mode 100644 index 0000000..6c2464f --- /dev/null +++ b/Tests/FindLibXml2/CMakeLists.txt @@ -0,0 +1,10 @@ +add_test(NAME FindLibXml2.Test COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindLibXml2/Test" + "${CMake_BINARY_DIR}/Tests/FindLibXml2/Test" + ${build_generator_args} + --build-project TestFindLibXml2 + --build-options ${build_options} + --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> + ) diff --git a/Tests/FindLibXml2/Test/CMakeLists.txt b/Tests/FindLibXml2/Test/CMakeLists.txt new file mode 100644 index 0000000..df5d8c3 --- /dev/null +++ b/Tests/FindLibXml2/Test/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.4) +project(TestFindLibXml2 C) +include(CTest) + +find_package(LibXml2 REQUIRED) + +add_definitions(-DCMAKE_EXPECTED_LibXml2_VERSION="${LIBXML2_VERSION_STRING}") + +add_executable(test_tgt main.c) +target_link_libraries(test_tgt LibXml2::LibXml2) +add_test(NAME test_tgt COMMAND test_tgt) + +add_executable(test_var main.c) +target_include_directories(test_var PRIVATE ${LIBXML2_INCLUDE_DIRS}) +target_link_libraries(test_var PRIVATE ${LIBXML2_LIBRARIES}) +add_test(NAME test_var COMMAND test_var) diff --git a/Tests/FindLibXml2/Test/main.c b/Tests/FindLibXml2/Test/main.c new file mode 100644 index 0000000..264f07d --- /dev/null +++ b/Tests/FindLibXml2/Test/main.c @@ -0,0 +1,19 @@ +#include <assert.h> +#include <libxml/tree.h> +#include <string.h> + +int main() +{ + xmlDoc* doc; + + xmlInitParser(); + + doc = xmlNewDoc(BAD_CAST "1.0"); + xmlFreeDoc(doc); + + assert(strstr(CMAKE_EXPECTED_LibXml2_VERSION, LIBXML_DOTTED_VERSION)); + + xmlCleanupParser(); + + return 0; +} diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt index 19d12e5..3d08704 100644 --- a/Tests/GeneratorExpression/CMakeLists.txt +++ b/Tests/GeneratorExpression/CMakeLists.txt @@ -57,6 +57,11 @@ add_custom_target(check-part1 ALL -Dtest_strequal_angle_r_comma=$<STREQUAL:$<ANGLE-R>,$<COMMA>> -Dtest_strequal_both_empty=$<STREQUAL:,> -Dtest_strequal_one_empty=$<STREQUAL:something,> + -Dtest_inlist_true=$<IN_LIST:a,a$<SEMICOLON>b> + -Dtest_inlist_false=$<IN_LIST:c,a$<SEMICOLON>b> + -Dtest_inlist_empty_1=$<IN_LIST:a,> + -Dtest_inlist_empty_2=$<IN_LIST:,a> + -Dtest_inlist_empty_3=$<IN_LIST:,> -Dtest_angle_r=$<ANGLE-R> -Dtest_comma=$<COMMA> -Dtest_semicolon=$<SEMICOLON> diff --git a/Tests/GeneratorExpression/check-part1.cmake b/Tests/GeneratorExpression/check-part1.cmake index 60b193f..41bcd6d 100644 --- a/Tests/GeneratorExpression/check-part1.cmake +++ b/Tests/GeneratorExpression/check-part1.cmake @@ -49,6 +49,11 @@ check(test_strequal_semicolon "1") check(test_strequal_angle_r_comma "0") check(test_strequal_both_empty "1") check(test_strequal_one_empty "0") +check(test_inlist_true "1") +check(test_inlist_false "0") +check(test_inlist_empty_1 "0") +check(test_inlist_empty_2 "0") +check(test_inlist_empty_3 "0") check(test_angle_r ">") check(test_comma ",") check(test_semicolon ";") diff --git a/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt b/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt index 2e6a5bd..f9c52b7 100644 --- a/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt +++ b/Tests/QtAutogen/RerunRccDepends/CMakeLists.txt @@ -45,8 +45,7 @@ file(TIMESTAMP "${rccDepBinGen}" rdGenBefore "${timeformat}") # - Change a resource files listed in the .qrc file # - Rebuild execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) -execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDepBD}/resPlain/input.txt") -execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDepBD}/resGen/input.txt") +file(TOUCH "${rccDepBD}/resPlain/input.txt" "${rccDepBD}/resGen/input.txt") execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result) if (result) message(SEND_ERROR "Second build of rccDepends failed.") @@ -97,8 +96,7 @@ file(TIMESTAMP "${rccDepBinGen}" rdGenBefore "${timeformat}") # - Change a newly added resource files listed in the .qrc file # - Rebuild execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) -execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDepBD}/resPlain/inputAdded.txt") -execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDepBD}/resGen/inputAdded.txt") +file(TOUCH "${rccDepBD}/resPlain/inputAdded.txt" "${rccDepBD}/resGen/inputAdded.txt") execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result) if (result) message(SEND_ERROR "Fourth build of rccDepends failed.") diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index d5bd297..ce80c13 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -188,6 +188,7 @@ if (QT4_FOUND) endif() add_RunCMake_test(CompatibleInterface) add_RunCMake_test(Syntax) +add_RunCMake_test(WorkingDirectory) add_RunCMake_test(add_custom_command) add_RunCMake_test(add_custom_target) @@ -339,6 +340,9 @@ add_RunCMake_test(CPackConfig) add_RunCMake_test(CPackInstallProperties) add_RunCMake_test(ExternalProject) add_RunCMake_test(FetchContent) +if(NOT CMake_TEST_EXTERNAL_CMAKE) + set(CTestCommandLine_ARGS -DTEST_AFFINITY=$<TARGET_FILE:testAffinity>) +endif() add_RunCMake_test(CTestCommandLine) add_RunCMake_test(CacheNewline) # Only run this test on unix platforms that support @@ -358,6 +362,11 @@ if(CMake_TEST_FindMatlab) add_RunCMake_test(FindMatlab) endif() +# UseSWIG related tests +if(CMake_TEST_UseSWIG) + add_RunCMake_test(UseSWIG) +endif() + add_executable(pseudo_emulator pseudo_emulator.c) add_executable(pseudo_emulator_custom_command pseudo_emulator_custom_command.c) add_RunCMake_test(CrosscompilingEmulator diff --git a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake index 0fafea5..3033c9c 100644 --- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake @@ -141,3 +141,23 @@ function(run_TestOutputSize) ) endfunction() run_TestOutputSize() + +function(run_TestAffinity) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/TestAffinity) + set(RunCMake_TEST_NO_CLEAN 1) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + # Create a test with affinity enabled. The default PROCESSORS + # value is 1, so our expected output checks that this is the + # number of processors in the mask. + file(WRITE "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" " + add_test(Affinity \"${TEST_AFFINITY}\") + set_tests_properties(Affinity PROPERTIES PROCESSOR_AFFINITY ON) +") + # Run ctest with a large parallel level so that the value is + # not responsible for capping the number of processors available. + run_cmake_command(TestAffinity ${CMAKE_CTEST_COMMAND} -V -j 64) +endfunction() +if(TEST_AFFINITY) + run_TestAffinity() +endif() diff --git a/Tests/RunCMake/CTestCommandLine/TestAffinity-stdout.txt b/Tests/RunCMake/CTestCommandLine/TestAffinity-stdout.txt new file mode 100644 index 0000000..e23d30b --- /dev/null +++ b/Tests/RunCMake/CTestCommandLine/TestAffinity-stdout.txt @@ -0,0 +1 @@ +1: CPU affinity (mask count is '1'|not supported on this platform)\. diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake index 2486259..f9a5cae 100644 --- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake +++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake @@ -34,6 +34,10 @@ run_cmake(OUTPUT_NAME-recursion) run_cmake(TARGET_PROPERTY-LOCATION) run_cmake(TARGET_PROPERTY-SOURCES) run_cmake(LINK_ONLY-not-linking) +run_cmake(TARGET_EXISTS-no-arg) +run_cmake(TARGET_EXISTS-empty-arg) +run_cmake(TARGET_EXISTS) +run_cmake(TARGET_EXISTS-not-a-target) run_cmake(ImportedTarget-TARGET_BUNDLE_DIR) run_cmake(ImportedTarget-TARGET_BUNDLE_CONTENT_DIR) diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-check.cmake new file mode 100644 index 0000000..c4c3a51 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-check.cmake @@ -0,0 +1,6 @@ +file(READ "${RunCMake_TEST_BINARY_DIR}/TARGET_EXISTS-generated.txt" content) + +set(expected "1") +if(NOT content STREQUAL expected) + set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]") +endif() diff --git a/Tests/RunCMake/add_library/OBJECTwithOnlyObjectSources-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-empty-arg-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/add_library/OBJECTwithOnlyObjectSources-result.txt +++ b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-empty-arg-result.txt diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-empty-arg-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-empty-arg-stderr.txt new file mode 100644 index 0000000..1df6e28 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-empty-arg-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at TARGET_EXISTS-empty-arg.cmake:2 \(file\): + Error evaluating generator expression: + + \$<TARGET_EXISTS:> + + \$<TARGET_EXISTS:tgt> expression requires a non-empty valid target name. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-empty-arg.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-empty-arg.cmake new file mode 100644 index 0000000..e387abc --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-empty-arg.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0070 NEW) +file(GENERATE OUTPUT TARGET_EXISTS-generated.txt CONTENT "$<TARGET_EXISTS:${empty}>") diff --git a/Tests/RunCMake/ObjectLibrary/ObjWithObj-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-no-arg-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/ObjectLibrary/ObjWithObj-result.txt +++ b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-no-arg-result.txt diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-no-arg-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-no-arg-stderr.txt new file mode 100644 index 0000000..69e6130 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-no-arg-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at TARGET_EXISTS-no-arg.cmake:2 \(file\): + Error evaluating generator expression: + + \$<TARGET_EXISTS> + + \$<TARGET_EXISTS> expression requires exactly one parameter. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-no-arg.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-no-arg.cmake new file mode 100644 index 0000000..0a5ce32 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-no-arg.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0070 NEW) +file(GENERATE OUTPUT TARGET_EXISTS-generated.txt CONTENT "$<TARGET_EXISTS>") diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-not-a-target-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-not-a-target-check.cmake new file mode 100644 index 0000000..35ba267 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-not-a-target-check.cmake @@ -0,0 +1,6 @@ +file(READ "${RunCMake_TEST_BINARY_DIR}/TARGET_EXISTS-not-a-target-generated.txt" content) + +set(expected "0") +if(NOT content STREQUAL expected) + set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]") +endif() diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-not-a-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-not-a-target.cmake new file mode 100644 index 0000000..d8a8d3e --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS-not-a-target.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0070 NEW) +file(GENERATE OUTPUT TARGET_EXISTS-not-a-target-generated.txt CONTENT "$<TARGET_EXISTS:just-random-string>") diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS.cmake new file mode 100644 index 0000000..9a83b34 --- /dev/null +++ b/Tests/RunCMake/GeneratorExpression/TARGET_EXISTS.cmake @@ -0,0 +1,3 @@ +cmake_policy(SET CMP0070 NEW) +add_custom_target(foo) +file(GENERATE OUTPUT TARGET_EXISTS-generated.txt CONTENT "$<TARGET_EXISTS:foo>") diff --git a/Tests/RunCMake/ObjectLibrary/BadObjSource2-stderr.txt b/Tests/RunCMake/ObjectLibrary/BadObjSource2-stderr.txt deleted file mode 100644 index b91ffd0..0000000 --- a/Tests/RunCMake/ObjectLibrary/BadObjSource2-stderr.txt +++ /dev/null @@ -1,9 +0,0 @@ -CMake Error at BadObjSource2.cmake:1 \(add_library\): - OBJECT library "A" contains: - - bad.obj - - but may contain only sources that compile, header files, and other files - that would not affect linking of a normal library. -Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/ObjectLibrary/CMakeLists.txt b/Tests/RunCMake/ObjectLibrary/CMakeLists.txt index a17c8cd..d1b0d2c 100644 --- a/Tests/RunCMake/ObjectLibrary/CMakeLists.txt +++ b/Tests/RunCMake/ObjectLibrary/CMakeLists.txt @@ -1,3 +1,3 @@ -cmake_minimum_required(VERSION 2.8.4) +cmake_minimum_required(VERSION 3.10) project(${RunCMake_TEST} C) include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/ObjectLibrary/ExportNotSupported-stderr.txt b/Tests/RunCMake/ObjectLibrary/ExportNotSupported-stderr.txt deleted file mode 100644 index 5420159..0000000 --- a/Tests/RunCMake/ObjectLibrary/ExportNotSupported-stderr.txt +++ /dev/null @@ -1,5 +0,0 @@ -CMake Error at ExportNotSupported.cmake:[0-9]+ \(export\): - export given OBJECT library "A" which may not be exported under Xcode with - multiple architectures. -Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/ObjectLibrary/ExportNotSupported.cmake b/Tests/RunCMake/ObjectLibrary/ExportNotSupported.cmake deleted file mode 100644 index a3f104e..0000000 --- a/Tests/RunCMake/ObjectLibrary/ExportNotSupported.cmake +++ /dev/null @@ -1,2 +0,0 @@ -add_library(A OBJECT a.c) -export(TARGETS A FILE AExport.cmake) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHS2-result.txt b/Tests/RunCMake/ObjectLibrary/InstallLinkedObj1-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/ObjectLibrary/LinkObjRHS2-result.txt +++ b/Tests/RunCMake/ObjectLibrary/InstallLinkedObj1-result.txt diff --git a/Tests/RunCMake/ObjectLibrary/InstallLinkedObj1-stderr.txt b/Tests/RunCMake/ObjectLibrary/InstallLinkedObj1-stderr.txt new file mode 100644 index 0000000..f2f0f94 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/InstallLinkedObj1-stderr.txt @@ -0,0 +1 @@ +CMake Error: install\(EXPORT "exp" ...\) includes target "UseA" which requires target "A" that is not in the export set. diff --git a/Tests/RunCMake/ObjectLibrary/InstallLinkedObj1.cmake b/Tests/RunCMake/ObjectLibrary/InstallLinkedObj1.cmake new file mode 100644 index 0000000..9e24609 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/InstallLinkedObj1.cmake @@ -0,0 +1,6 @@ +add_library(A OBJECT a.c) +add_library(UseA STATIC) +target_link_libraries(UseA PUBLIC A) + +install(TARGETS UseA EXPORT exp ARCHIVE DESTINATION lib) +install(EXPORT exp DESTINATION lib/cmake/exp) diff --git a/Tests/RunCMake/ObjectLibrary/InstallLinkedObj2.cmake b/Tests/RunCMake/ObjectLibrary/InstallLinkedObj2.cmake new file mode 100644 index 0000000..cdda962 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/InstallLinkedObj2.cmake @@ -0,0 +1,6 @@ +add_library(A OBJECT a.c) +add_library(UseA STATIC) +target_link_libraries(UseA PUBLIC A) + +install(TARGETS UseA A EXPORT exp ARCHIVE DESTINATION lib) +install(EXPORT exp DESTINATION lib/cmake/exp) diff --git a/Tests/RunCMake/ObjectLibrary/InstallNotSupported-stderr.txt b/Tests/RunCMake/ObjectLibrary/InstallNotSupported-stderr.txt index 35a0e4f..a7004c1 100644 --- a/Tests/RunCMake/ObjectLibrary/InstallNotSupported-stderr.txt +++ b/Tests/RunCMake/ObjectLibrary/InstallNotSupported-stderr.txt @@ -1,5 +1,5 @@ CMake Error at InstallNotSupported.cmake:[0-9]+ \(install\): - install TARGETS given OBJECT library "A" which may not be installed under - Xcode with multiple architectures. + install TARGETS given OBJECT library "A" whose objects may not be installed + under Xcode with multiple architectures. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjLHS-stderr.txt b/Tests/RunCMake/ObjectLibrary/LinkObjLHS-stderr.txt deleted file mode 100644 index 90e828b..0000000 --- a/Tests/RunCMake/ObjectLibrary/LinkObjLHS-stderr.txt +++ /dev/null @@ -1,4 +0,0 @@ -CMake Error at LinkObjLHS.cmake:2 \(target_link_libraries\): - Object library target "AnObjLib" may not link to anything. -Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjLHS.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjLHS.cmake deleted file mode 100644 index 5d7831a..0000000 --- a/Tests/RunCMake/ObjectLibrary/LinkObjLHS.cmake +++ /dev/null @@ -1,2 +0,0 @@ -add_library(AnObjLib OBJECT a.c) -target_link_libraries(AnObjLib OtherLib) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjLHSShared.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjLHSShared.cmake new file mode 100644 index 0000000..4aa7bba --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/LinkObjLHSShared.cmake @@ -0,0 +1,7 @@ +project(LinkObjLHSShared C) + +add_library(OtherLib SHARED a.c) +target_compile_definitions(OtherLib INTERFACE REQUIRED) + +add_library(AnObjLib OBJECT requires.c) +target_link_libraries(AnObjLib OtherLib) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjLHSStatic.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjLHSStatic.cmake new file mode 100644 index 0000000..261bee7 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/LinkObjLHSStatic.cmake @@ -0,0 +1,7 @@ +project(LinkObjLHSStatic C) + +add_library(OtherLib STATIC a.c) +target_compile_definitions(OtherLib INTERFACE REQUIRED) + +add_library(AnObjLib OBJECT requires.c) +target_link_libraries(AnObjLib OtherLib) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt b/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt deleted file mode 100644 index d5ee4f9..0000000 --- a/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt +++ /dev/null @@ -1,6 +0,0 @@ -CMake Error at LinkObjRHS1.cmake:3 \(target_link_libraries\): - Target "AnObjLib" of type OBJECT_LIBRARY may not be linked into another - target. One may link only to INTERFACE, STATIC or SHARED libraries, or to - executables with the ENABLE_EXPORTS property set. -Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHS1.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjRHS1.cmake deleted file mode 100644 index 113d6a8..0000000 --- a/Tests/RunCMake/ObjectLibrary/LinkObjRHS1.cmake +++ /dev/null @@ -1,3 +0,0 @@ -add_library(A STATIC a.c) -add_library(AnObjLib OBJECT a.c) -target_link_libraries(A AnObjLib) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHS2-stderr.txt b/Tests/RunCMake/ObjectLibrary/LinkObjRHS2-stderr.txt deleted file mode 100644 index 3295fca..0000000 --- a/Tests/RunCMake/ObjectLibrary/LinkObjRHS2-stderr.txt +++ /dev/null @@ -1,6 +0,0 @@ -CMake Error at LinkObjRHS2.cmake:1 \(add_library\): - Target "A" links to OBJECT library "AnObjLib" but this is not allowed. One - may link only to STATIC or SHARED libraries, or to executables with the - ENABLE_EXPORTS property set. -Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHS2.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjRHS2.cmake deleted file mode 100644 index 6163729..0000000 --- a/Tests/RunCMake/ObjectLibrary/LinkObjRHS2.cmake +++ /dev/null @@ -1,3 +0,0 @@ -add_library(A SHARED a.c) -target_link_libraries(A AnObjLib) -add_library(AnObjLib OBJECT a.c) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject-build-result.txt b/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject-build-result.txt new file mode 100644 index 0000000..e27f06b --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject-build-result.txt @@ -0,0 +1 @@ +[1-9][0-9]* diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject-build-stdout.txt b/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject-build-stdout.txt new file mode 100644 index 0000000..4eeb096 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject-build-stdout.txt @@ -0,0 +1 @@ +REQUIRED needs to be defined diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject.cmake new file mode 100644 index 0000000..db571a3 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject.cmake @@ -0,0 +1,12 @@ +cmake_policy(SET CMP0022 NEW) + +enable_language(C) + +add_library(AnObjLib OBJECT a.c) +target_compile_definitions(AnObjLib INTERFACE REQUIRED) + +add_library(AnotherObjLib OBJECT b.c) +target_link_libraries(AnotherObjLib PRIVATE AnObjLib) + +add_executable(exe exe.c) +target_link_libraries(exe AnotherObjLib) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject2-build-result.txt b/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject2-build-result.txt new file mode 100644 index 0000000..e27f06b --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject2-build-result.txt @@ -0,0 +1 @@ +[1-9][0-9]* diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject2.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject2.cmake new file mode 100644 index 0000000..6bb8d5e --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/LinkObjRHSObject2.cmake @@ -0,0 +1,12 @@ +cmake_policy(SET CMP0022 NEW) + +enable_language(C) + +add_library(AnObjLib OBJECT a.c) +target_compile_definitions(AnObjLib INTERFACE REQUIRED) + +add_library(AnotherObjLib OBJECT b.c) +target_link_libraries(AnotherObjLib PUBLIC AnObjLib) + +add_executable(exe exe.c) +target_link_libraries(exe AnotherObjLib) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHSShared.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjRHSShared.cmake new file mode 100644 index 0000000..b9030b3 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/LinkObjRHSShared.cmake @@ -0,0 +1,13 @@ +enable_language(C) + +add_definitions(-DCOMPILE_FOR_SHARED_LIB) + +add_library(AnObjLib OBJECT a.c) +target_compile_definitions(AnObjLib INTERFACE REQUIRED) +set_target_properties(AnObjLib PROPERTIES POSITION_INDEPENDENT_CODE ON) + +add_library(A SHARED b.c $<TARGET_OBJECTS:AnObjLib>) +target_link_libraries(A PUBLIC AnObjLib) + +add_executable(exe exe.c) +target_link_libraries(exe A) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHSShared2.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjRHSShared2.cmake new file mode 100644 index 0000000..e2e5fa2 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/LinkObjRHSShared2.cmake @@ -0,0 +1,14 @@ +enable_language(C) + +add_definitions(-DCOMPILE_FOR_SHARED_LIB) + +add_library(AnObjLib OBJECT a.c) +target_compile_definitions(AnObjLib INTERFACE REQUIRED) +set_target_properties(AnObjLib PROPERTIES POSITION_INDEPENDENT_CODE ON) + +add_library(A SHARED b.c) +target_link_libraries(A PRIVATE AnObjLib) +target_compile_definitions(A INTERFACE $<TARGET_PROPERTY:AnObjLib,INTERFACE_COMPILE_DEFINITIONS>) + +add_executable(exe exe.c) +target_link_libraries(exe A) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHSStatic.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjRHSStatic.cmake new file mode 100644 index 0000000..73fad06 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/LinkObjRHSStatic.cmake @@ -0,0 +1,10 @@ +enable_language(C) + +add_library(AnObjLib OBJECT a.c) +target_compile_definitions(AnObjLib INTERFACE REQUIRED) + +add_library(A STATIC b.c $<TARGET_OBJECTS:AnObjLib>) +target_link_libraries(A PUBLIC AnObjLib) + +add_executable(exe exe.c) +target_link_libraries(exe A) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHSStatic2.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjRHSStatic2.cmake new file mode 100644 index 0000000..9e1ab6d --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/LinkObjRHSStatic2.cmake @@ -0,0 +1,11 @@ +enable_language(C) + +add_library(AnObjLib OBJECT a.c) +target_compile_definitions(AnObjLib INTERFACE REQUIRED) + +add_library(A STATIC b.c) +target_link_libraries(A PRIVATE AnObjLib) +target_compile_definitions(A INTERFACE $<TARGET_PROPERTY:AnObjLib,INTERFACE_COMPILE_DEFINITIONS>) + +add_executable(exe exe.c) +target_link_libraries(exe A) diff --git a/Tests/RunCMake/ObjectLibrary/ObjWithObj-stderr.txt b/Tests/RunCMake/ObjectLibrary/ObjWithObj-stderr.txt deleted file mode 100644 index d67b4ae..0000000 --- a/Tests/RunCMake/ObjectLibrary/ObjWithObj-stderr.txt +++ /dev/null @@ -1,4 +0,0 @@ -CMake Error at ObjWithObj.cmake:2 \(add_library\): - Only executables and non-OBJECT libraries may reference target objects. -Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake index b8eed73..c73732f 100644 --- a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake +++ b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake @@ -6,17 +6,46 @@ run_cmake(BadSourceExpression3) run_cmake(BadObjSource1) run_cmake(BadObjSource2) if(RunCMake_GENERATOR STREQUAL "Xcode" AND "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]") - run_cmake(ExportNotSupported) run_cmake(ImportNotSupported) run_cmake(InstallNotSupported) else() - run_cmake(Export) run_cmake(Import) run_cmake(Install) + run_cmake(InstallLinkedObj1) + run_cmake(InstallLinkedObj2) endif() -run_cmake(LinkObjLHS) -run_cmake(LinkObjRHS1) -run_cmake(LinkObjRHS2) +run_cmake(Export) + +function (run_object_lib_build name) + # Use a single build tree for a few tests without cleaning. + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build) + set(RunCMake_TEST_NO_CLEAN 1) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + run_cmake(${name}) + run_cmake_command(${name}-build ${CMAKE_COMMAND} --build .) +endfunction () + +function (run_object_lib_build2 name) + # Use a single build tree for a few tests without cleaning. + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build) + set(RunCMake_TEST_NO_CLEAN 1) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + run_cmake(${name}) + set(RunCMake_TEST_OUTPUT_MERGE 1) + run_cmake_command(${name}-build ${CMAKE_COMMAND} --build .) +endfunction () + +run_object_lib_build(LinkObjLHSShared) +run_object_lib_build(LinkObjLHSStatic) +run_object_lib_build(LinkObjRHSShared) +run_object_lib_build(LinkObjRHSStatic) +run_object_lib_build2(LinkObjRHSObject) +run_object_lib_build(LinkObjRHSShared2) +run_object_lib_build(LinkObjRHSStatic2) +run_object_lib_build2(LinkObjRHSObject2) + run_cmake(MissingSource) run_cmake(ObjWithObj) run_cmake(OwnSources) diff --git a/Tests/RunCMake/ObjectLibrary/a.c b/Tests/RunCMake/ObjectLibrary/a.c index 1636303..5beb3f1 100644 --- a/Tests/RunCMake/ObjectLibrary/a.c +++ b/Tests/RunCMake/ObjectLibrary/a.c @@ -1,4 +1,10 @@ -int a(void) +#if defined(_WIN32) && defined(COMPILE_FOR_SHARED_LIB) +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +EXPORT int a(void) { return 0; } diff --git a/Tests/RunCMake/ObjectLibrary/b.c b/Tests/RunCMake/ObjectLibrary/b.c index 6751907..7549abf 100644 --- a/Tests/RunCMake/ObjectLibrary/b.c +++ b/Tests/RunCMake/ObjectLibrary/b.c @@ -1,4 +1,14 @@ -int b(void) +#if defined(_WIN32) && defined(COMPILE_FOR_SHARED_LIB) +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +extern int a(void); +EXPORT int b() { - return 0; + return a(); } +#ifndef REQUIRED +#error "REQUIRED needs to be defined" +#endif diff --git a/Tests/RunCMake/ObjectLibrary/exe.c b/Tests/RunCMake/ObjectLibrary/exe.c new file mode 100644 index 0000000..6efdae7 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/exe.c @@ -0,0 +1,14 @@ +#if defined(_WIN32) && defined(COMPILE_FOR_SHARED_LIB) +#define IMPORT __declspec(dllimport) +#else +#define IMPORT +#endif + +extern IMPORT int b(void); +int main() +{ + return b(); +} +#ifndef REQUIRED +#error "REQUIRED needs to be defined" +#endif diff --git a/Tests/RunCMake/ObjectLibrary/requires.c b/Tests/RunCMake/ObjectLibrary/requires.c new file mode 100644 index 0000000..d524952 --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/requires.c @@ -0,0 +1,8 @@ +#ifdef REQUIRED +int required() +{ + return 0; +} +#else +#error "REQUIRED not defined" +#endif diff --git a/Tests/RunCMake/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake index e688830..36a122f 100644 --- a/Tests/RunCMake/RunCMake.cmake +++ b/Tests/RunCMake/RunCMake.cmake @@ -112,6 +112,8 @@ function(run_cmake test) "|clang[^:]*: warning: the object size sanitizer has no effect at -O0, but is explicitly enabled:" "|Error kstat returned" "|Hit xcodebuild bug" + "|ld: 0711-224 WARNING: Duplicate symbol: .__init_aix_libgcc_cxa_atexit" + "|ld: 0711-345 Use the -bloadmap or -bnoquiet option to obtain more information" "|[^\n]*is a member of multiple groups" "|[^\n]*from Time Machine by path" "|[^\n]*Bullseye Testing Technology" diff --git a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt index 8d5139d..5af6fcd 100644 --- a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt +++ b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt @@ -23,6 +23,7 @@ \* CMP0065 \* CMP0068 \* CMP0069 + \* CMP0073 Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/UseSWIG/BasicConfiguration.cmake b/Tests/RunCMake/UseSWIG/BasicConfiguration.cmake new file mode 100644 index 0000000..94d8dd3 --- /dev/null +++ b/Tests/RunCMake/UseSWIG/BasicConfiguration.cmake @@ -0,0 +1,68 @@ + +find_package(SWIG REQUIRED) +include(${SWIG_USE_FILE}) + +unset(SWIG_LANG_TYPE) +unset(SWIG_LANG_INCLUDE_DIRECTORIES) +unset(SWIG_LANG_DEFINITIONS) +unset(SWIG_LANG_OPTIONS) +unset(SWIG_LANG_LIBRARIES) + +if(${language} MATCHES python) + find_package(PythonInterp REQUIRED) + find_package(PythonLibs REQUIRED) + set(SWIG_LANG_INCLUDE_DIRECTORIES ${PYTHON_INCLUDE_PATH}) + set(SWIG_LANG_LIBRARIES ${PYTHON_LIBRARIES}) +endif() +if(${language} MATCHES perl) + find_package(Perl REQUIRED) + find_package(PerlLibs REQUIRED) + set(SWIG_LANG_INCLUDE_DIRECTORIES ${PERL_INCLUDE_PATH}) + separate_arguments(c_flags UNIX_COMMAND "${PERL_EXTRA_C_FLAGS}") + set(SWIG_LANG_OPTIONS ${c_flags}) + set(SWIG_LANG_LIBRARIES ${PERL_LIBRARY}) +endif() +if(${language} MATCHES tcl) + find_package(TCL REQUIRED) + set(SWIG_LANG_INCLUDE_DIRECTORIES ${TCL_INCLUDE_PATH}) + set(SWIG_LANG_LIBRARIES ${TCL_LIBRARY}) +endif() +if(${language} MATCHES ruby) + find_package(Ruby REQUIRED) + set(SWIG_LANG_INCLUDE_DIRECTORIES ${RUBY_INCLUDE_PATH}) + set(SWIG_LANG_LIBRARIES ${RUBY_LIBRARY}) +endif() +if(${language} MATCHES php4) + find_package(PHP4 REQUIRED) + set(SWIG_LANG_INCLUDE_DIRECTORIES ${PHP4_INCLUDE_PATH}) + set(SWIG_LANG_LIBRARIES ${PHP4_LIBRARY}) +endif() +if(${language} MATCHES pike) + find_package(Pike REQUIRED) + set(SWIG_LANG_INCLUDE_DIRECTORIES ${PIKE_INCLUDE_PATH}) + set(SWIG_LANG_LIBRARIES ${PIKE_LIBRARY}) +endif() +if(${language} MATCHES lua) + find_package(Lua REQUIRED) + set(SWIG_LANG_INCLUDE_DIRECTORIES ${LUA_INCLUDE_DIR}) + set(SWIG_LANG_TYPE TYPE SHARED) + set(SWIG_LANG_LIBRARIES ${LUA_LIBRARIES}) +endif() + +unset(CMAKE_SWIG_FLAGS) + +set (CMAKE_INCLUDE_CURRENT_DIR ON) + +set_property(SOURCE example.i PROPERTY CPLUSPLUS ON) +set_property(SOURCE example.i PROPERTY COMPILE_OPTIONS -includeall) + +set_property(SOURCE example.i PROPERTY GENERATED_INCLUDE_DIRECTORIES ${SWIG_LANG_INCLUDE_DIRECTORIES}) +set_property(SOURCE example.i PROPERTY GENERATED_COMPILE_DEFINITIONS ${SWIG_LANG_DEFINITIONS}) +set_property(SOURCE example.i PROPERTY GENERATED_COMPILE_OPTIONS ${SWIG_LANG_OPTIONS}) + + +SWIG_ADD_LIBRARY(example + LANGUAGE "${language}" + ${SWIG_LANG_TYPE} + SOURCES example.i example.cxx) +TARGET_LINK_LIBRARIES(example PRIVATE ${SWIG_LANG_LIBRARIES}) diff --git a/Tests/RunCMake/UseSWIG/BasicPerl.cmake b/Tests/RunCMake/UseSWIG/BasicPerl.cmake new file mode 100644 index 0000000..67ad6bc --- /dev/null +++ b/Tests/RunCMake/UseSWIG/BasicPerl.cmake @@ -0,0 +1,18 @@ + +set(language "perl") + +include (BasicConfiguration.cmake) + +if (WIN32) + file (TO_CMAKE_PATH "$ENV{PATH}" perl_path) + string (REPLACE ";" "$<SEMICOLON>" perl_path "${perl_path}") + set (perl_env "PATH=$<TARGET_FILE_DIR:example>$<SEMICOLON>${perl_path}") +else() + set (perl_env "LD_LIBRARY_PATH=$<TARGET_FILE_DIR:example>") +endif() + +add_custom_target (RunTest + COMMAND "${CMAKE_COMMAND}" -E env "${perl_env}" + "${PERL_EXECUTABLE}" "-I$<TARGET_FILE_DIR:example>" + "${CMAKE_CURRENT_SOURCE_DIR}/runme.pl" + DEPENDS example) diff --git a/Tests/RunCMake/UseSWIG/BasicPython.cmake b/Tests/RunCMake/UseSWIG/BasicPython.cmake new file mode 100644 index 0000000..0d8c824 --- /dev/null +++ b/Tests/RunCMake/UseSWIG/BasicPython.cmake @@ -0,0 +1,9 @@ + +set(language "python") + +include (BasicConfiguration.cmake) + +add_custom_target (RunTest + COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:example>" + "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/runme.py" + DEPENDS example) diff --git a/Tests/RunCMake/UseSWIG/CMakeLists.txt b/Tests/RunCMake/UseSWIG/CMakeLists.txt new file mode 100644 index 0000000..f452db1 --- /dev/null +++ b/Tests/RunCMake/UseSWIG/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.4) +project(${RunCMake_TEST} CXX) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/SwigTest/CMakeLists.txt b/Tests/RunCMake/UseSWIG/LegacyConfiguration.cmake index 65f5c93..3ce0790 100644 --- a/Tests/SwigTest/CMakeLists.txt +++ b/Tests/RunCMake/UseSWIG/LegacyConfiguration.cmake @@ -1,54 +1,55 @@ -set(language "python") -cmake_minimum_required (VERSION 2.6) - -project(example_${language}_class) +# Prevent deprecated warnings from new UseSWIG module +set (CMAKE_WARN_DEPRECATED FALSE) find_package(SWIG REQUIRED) include(${SWIG_USE_FILE}) unset(SWIG_LANG_TYPE) if(${language} MATCHES python) - find_package(PythonLibs) + find_package(PythonInterp REQUIRED) + find_package(PythonLibs REQUIRED) include_directories(${PYTHON_INCLUDE_PATH}) set(SWIG_LANG_LIBRARIES ${PYTHON_LIBRARIES}) endif() if(${language} MATCHES perl) - find_package(PerlLibs) + find_package(Perl REQUIRED) + find_package(PerlLibs REQUIRED) include_directories(${PERL_INCLUDE_PATH}) - add_definitions(${PERL_EXTRA_C_FLAGS}) + separate_arguments(c_flags UNIX_COMMAND "${PERL_EXTRA_C_FLAGS}") + add_compile_options(${c_flags}) set(SWIG_LANG_LIBRARIES ${PERL_LIBRARY}) endif() if(${language} MATCHES tcl) - find_package(TCL) + find_package(TCL REQUIRED) include_directories(${TCL_INCLUDE_PATH}) set(SWIG_LANG_LIBRARIES ${TCL_LIBRARY}) endif() if(${language} MATCHES ruby) - find_package(Ruby) + find_package(Ruby REQUIRED) include_directories(${RUBY_INCLUDE_PATH}) set(SWIG_LANG_LIBRARIES ${RUBY_LIBRARY}) endif() if(${language} MATCHES php4) - find_package(PHP4) + find_package(PHP4 REQUIRED) include_directories(${PHP4_INCLUDE_PATH}) set(SWIG_LANG_LIBRARIES ${PHP4_LIBRARY}) endif() if(${language} MATCHES pike) - find_package(Pike) + find_package(Pike REQUIRED) include_directories(${PIKE_INCLUDE_PATH}) set(SWIG_LANG_LIBRARIES ${PIKE_LIBRARY}) endif() if(${language} MATCHES lua) - find_package(Lua) + find_package(Lua REQUIRED) include_directories(${LUA_INCLUDE_DIR}) set(SWIG_LANG_TYPE TYPE SHARED) set(SWIG_LANG_LIBRARIES ${LUA_LIBRARIES}) endif() -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +unset(CMAKE_SWIG_FLAGS) -set(CMAKE_SWIG_FLAGS "") +include_directories(${CMAKE_CURRENT_LIST_DIR}) set_source_files_properties(example.i PROPERTIES CPLUSPLUS ON) set_source_files_properties(example.i PROPERTIES SWIG_FLAGS "-includeall") diff --git a/Tests/RunCMake/UseSWIG/LegacyPerl.cmake b/Tests/RunCMake/UseSWIG/LegacyPerl.cmake new file mode 100644 index 0000000..3428c46 --- /dev/null +++ b/Tests/RunCMake/UseSWIG/LegacyPerl.cmake @@ -0,0 +1,18 @@ + +set(language "perl") + +include (LegacyConfiguration.cmake) + +if (WIN32) + file (TO_CMAKE_PATH "$ENV{PATH}" perl_path) + string (REPLACE ";" "$<SEMICOLON>" perl_path "${perl_path}") + set (perl_env "PATH=$<TARGET_FILE_DIR:${SWIG_MODULE_example_REAL_NAME}>$<SEMICOLON>${perl_path}") +else() + set (perl_env "LD_LIBRARY_PATH=$<TARGET_FILE_DIR:${SWIG_MODULE_example_REAL_NAME}>") +endif() + +add_custom_target (RunTest + COMMAND "${CMAKE_COMMAND}" -E env "${perl_env}" + "${PERL_EXECUTABLE}" "-I$<TARGET_FILE_DIR:${SWIG_MODULE_example_REAL_NAME}>" + "${CMAKE_CURRENT_SOURCE_DIR}/runme.pl" + DEPENDS ${SWIG_MODULE_example_REAL_NAME}) diff --git a/Tests/RunCMake/UseSWIG/LegacyPython.cmake b/Tests/RunCMake/UseSWIG/LegacyPython.cmake new file mode 100644 index 0000000..8b47aa2 --- /dev/null +++ b/Tests/RunCMake/UseSWIG/LegacyPython.cmake @@ -0,0 +1,9 @@ + +set(language "python") + +include (LegacyConfiguration.cmake) + +add_custom_target (RunTest + COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:${SWIG_MODULE_example_REAL_NAME}>" + "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/runme.py" + DEPENDS ${SWIG_MODULE_example_REAL_NAME}) diff --git a/Tests/RunCMake/UseSWIG/MultipleModules.cmake b/Tests/RunCMake/UseSWIG/MultipleModules.cmake new file mode 100644 index 0000000..e3d579f --- /dev/null +++ b/Tests/RunCMake/UseSWIG/MultipleModules.cmake @@ -0,0 +1,30 @@ + +find_package(SWIG REQUIRED) +include(${SWIG_USE_FILE}) + +find_package(PythonLibs REQUIRED) +find_package(PerlLibs REQUIRED) + +unset(CMAKE_SWIG_FLAGS) + +set (CMAKE_INCLUDE_CURRENT_DIR ON) + +set_property(SOURCE example.i PROPERTY CPLUSPLUS ON) +set_property(SOURCE example.i PROPERTY COMPILE_OPTIONS -includeall) + +set_property(SOURCE example.i PROPERTY GENERATED_INCLUDE_DIRECTORIES ${PYTHON_INCLUDE_PATH}) + +swig_add_library(example1 + LANGUAGE python + SOURCES example.i example.cxx) +target_link_libraries(example1 PRIVATE ${PYTHON_LIBRARIES}) + +# re-use sample interface file for another plugin +set_property(SOURCE example.i PROPERTY GENERATED_INCLUDE_DIRECTORIES ${PERL_INCLUDE_PATH}) +separate_arguments(c_flags UNIX_COMMAND "${PERL_EXTRA_C_FLAGS}") +set_property(SOURCE example.i PROPERTY GENERATED_COMPILE_OPTIONS ${c_flags}) + +swig_add_library(example2 + LANGUAGE perl + SOURCES example.i example.cxx) +target_link_libraries(example2 PRIVATE ${PERL_LIBRARY}) diff --git a/Tests/RunCMake/UseSWIG/RunCMakeTest.cmake b/Tests/RunCMake/UseSWIG/RunCMakeTest.cmake new file mode 100644 index 0000000..c63ff2e --- /dev/null +++ b/Tests/RunCMake/UseSWIG/RunCMakeTest.cmake @@ -0,0 +1,23 @@ +include(RunCMake) + +function(run_SWIG test) + cmake_parse_arguments(_SWIG_TEST "" "TARGET" "" ${ARGN}) + if (_SWIG_TEST_TARGET) + list (INSERT _SWIG_TEST_TARGET 0 --target) + endif() + + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build) + set(RunCMake_TEST_NO_CLEAN 1) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + run_cmake(${test}) + run_cmake_command(${test}-test ${CMAKE_COMMAND} --build ${RunCMake_TEST_BINARY_DIR} ${_SWIG_TEST_TARGET}) +endfunction() + +run_SWIG(LegacyPython TARGET RunTest) +run_SWIG(LegacyPerl TARGET RunTest) + +run_SWIG(BasicPython TARGET RunTest) +run_SWIG(BasicPerl TARGET RunTest) + +run_SWIG(MultipleModules) diff --git a/Tests/SwigTest/example.cxx b/Tests/RunCMake/UseSWIG/example.cxx index 961d6dd..961d6dd 100644 --- a/Tests/SwigTest/example.cxx +++ b/Tests/RunCMake/UseSWIG/example.cxx diff --git a/Tests/SwigTest/example.h b/Tests/RunCMake/UseSWIG/example.h index 366deb0..366deb0 100644 --- a/Tests/SwigTest/example.h +++ b/Tests/RunCMake/UseSWIG/example.h diff --git a/Tests/SwigTest/example.i b/Tests/RunCMake/UseSWIG/example.i index 75700b3..fbdf724 100644 --- a/Tests/SwigTest/example.i +++ b/Tests/RunCMake/UseSWIG/example.i @@ -7,4 +7,3 @@ /* Let's just grab the original header file here */ %include "example.h" - diff --git a/Tests/SwigTest/runme.php4 b/Tests/RunCMake/UseSWIG/runme.php4 index 653ced2..653ced2 100644 --- a/Tests/SwigTest/runme.php4 +++ b/Tests/RunCMake/UseSWIG/runme.php4 diff --git a/Tests/SwigTest/runme.pike b/Tests/RunCMake/UseSWIG/runme.pike index ec28dd7..ec28dd7 100755..100644 --- a/Tests/SwigTest/runme.pike +++ b/Tests/RunCMake/UseSWIG/runme.pike diff --git a/Tests/SwigTest/runme.pl b/Tests/RunCMake/UseSWIG/runme.pl index 5bfb3d8..965e063 100644 --- a/Tests/SwigTest/runme.pl +++ b/Tests/RunCMake/UseSWIG/runme.pl @@ -54,4 +54,3 @@ examplec::delete_Shape($s); print $examplec::Shape_nshapes," shapes remain\n"; print "Goodbye\n"; - diff --git a/Tests/RunCMake/UseSWIG/runme.py b/Tests/RunCMake/UseSWIG/runme.py new file mode 100644 index 0000000..af5e07d --- /dev/null +++ b/Tests/RunCMake/UseSWIG/runme.py @@ -0,0 +1,52 @@ +# file: runme.py + +# This file illustrates the shadow-class C++ interface generated +# by SWIG. + +from __future__ import print_function + +import example + +# ----- Object creation ----- + +print ("Creating some objects:") +c = example.Circle(10) +print (" Created circle", c) +s = example.Square(10) +print (" Created square", s) + +# ----- Access a static member ----- + +print ("\nA total of", example.cvar.Shape_nshapes,"shapes were created") + +# ----- Member data access ----- + +# Set the location of the object + +c.x = 20 +c.y = 30 + +s.x = -10 +s.y = 5 + +print ("\nHere is their current position:") +print (" Circle = (%f, %f)" % (c.x,c.y)) +print (" Square = (%f, %f)" % (s.x,s.y)) + +# ----- Call some methods ----- + +print ("\nHere are some properties of the shapes:") +for o in [c,s]: + print (" ", o) + print (" area = ", o.area()) + print (" perimeter = ", o.perimeter()) + +print ("\nGuess I'll clean up now") + +# Note: this invokes the virtual destructor +del c +del s + +s = 3 +print (example.cvar.Shape_nshapes,"shapes remain") +print ("Goodbye") diff --git a/Tests/SwigTest/runme.rb b/Tests/RunCMake/UseSWIG/runme.rb index de73bcd..de73bcd 100644 --- a/Tests/SwigTest/runme.rb +++ b/Tests/RunCMake/UseSWIG/runme.rb diff --git a/Tests/SwigTest/runme.tcl b/Tests/RunCMake/UseSWIG/runme.tcl index c7f4725..6055cf6 100644 --- a/Tests/SwigTest/runme.tcl +++ b/Tests/RunCMake/UseSWIG/runme.tcl @@ -47,4 +47,3 @@ rename s "" puts "$Shape_nshapes shapes remain" puts "Goodbye" - diff --git a/Tests/SwigTest/runme2.tcl b/Tests/RunCMake/UseSWIG/runme2.tcl index 88ec2f6..d0b5c21 100644 --- a/Tests/SwigTest/runme2.tcl +++ b/Tests/RunCMake/UseSWIG/runme2.tcl @@ -67,4 +67,3 @@ delete_Shape $s puts "$Shape_nshapes shapes remain" puts "Goodbye" - diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index 7100b31..afe9d6d 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -3,6 +3,7 @@ run_cmake(VsConfigurationType) run_cmake(VsTargetsFileReferences) run_cmake(VsCustomProps) run_cmake(VsDebuggerWorkingDir) +run_cmake(VsDebuggerCommand) run_cmake(VsCSharpCustomTags) run_cmake(VsCSharpReferenceProps) run_cmake(VsCSharpWithoutSources) diff --git a/Tests/RunCMake/VS10Project/VsCSharpCustomTags.cmake b/Tests/RunCMake/VS10Project/VsCSharpCustomTags.cmake index 45766a0..96be54b 100644 --- a/Tests/RunCMake/VS10Project/VsCSharpCustomTags.cmake +++ b/Tests/RunCMake/VS10Project/VsCSharpCustomTags.cmake @@ -16,8 +16,7 @@ set(fileNames) foreach(e ${fileExtensions}) set(currentFile "${CMAKE_CURRENT_BINARY_DIR}/foo.${e}") list(APPEND fileNames ${currentFile}) - execute_process(COMMAND ${CMAKE_COMMAND} -E touch - "${currentFile}") + file(TOUCH "${currentFile}") string(TOUPPER ${e} eUC) set_source_files_properties("${currentFile}" PROPERTIES diff --git a/Tests/RunCMake/VS10Project/VsDebuggerCommand-check.cmake b/Tests/RunCMake/VS10Project/VsDebuggerCommand-check.cmake new file mode 100644 index 0000000..0ded780 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsDebuggerCommand-check.cmake @@ -0,0 +1,22 @@ +set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj") +if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.") + return() +endif() + +set(debuggerCommandSet FALSE) + +file(STRINGS "${vcProjectFile}" lines) +foreach(line IN LISTS lines) + if(line MATCHES "^ *<LocalDebuggerCommand[^>]*>([^<>]+)</LocalDebuggerCommand>$") + if("${CMAKE_MATCH_1}" STREQUAL "my-debugger-command") + message(STATUS "foo.vcxproj has debugger command set") + set(debuggerCommandSet TRUE) + endif() + endif() +endforeach() + +if(NOT debuggerCommandSet) + set(RunCMake_TEST_FAILED "LocalDebuggerCommand not found or not set correctly.") + return() +endif() diff --git a/Tests/RunCMake/VS10Project/VsDebuggerCommand.cmake b/Tests/RunCMake/VS10Project/VsDebuggerCommand.cmake new file mode 100644 index 0000000..e29adc4 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsDebuggerCommand.cmake @@ -0,0 +1,5 @@ +enable_language(CXX) +add_library(foo foo.cpp) + +set_target_properties(foo PROPERTIES + VS_DEBUGGER_COMMAND "my-debugger-command") diff --git a/Tests/RunCMake/WorkingDirectory/CMakeLists.txt.in b/Tests/RunCMake/WorkingDirectory/CMakeLists.txt.in new file mode 100644 index 0000000..46047b8 --- /dev/null +++ b/Tests/RunCMake/WorkingDirectory/CMakeLists.txt.in @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.11) +project(@CASE_NAME@ NONE) +include("@RunCMake_SOURCE_DIR@/@CASE_NAME@.cmake") diff --git a/Tests/RunCMake/WorkingDirectory/CTestConfig.cmake.in b/Tests/RunCMake/WorkingDirectory/CTestConfig.cmake.in new file mode 100644 index 0000000..0226230 --- /dev/null +++ b/Tests/RunCMake/WorkingDirectory/CTestConfig.cmake.in @@ -0,0 +1 @@ +set(CTEST_PROJECT_NAME "CTestTestWorkingDir.@CASE_NAME@") diff --git a/Tests/RunCMake/WorkingDirectory/RunCMakeTest.cmake b/Tests/RunCMake/WorkingDirectory/RunCMakeTest.cmake new file mode 100644 index 0000000..a7685ae --- /dev/null +++ b/Tests/RunCMake/WorkingDirectory/RunCMakeTest.cmake @@ -0,0 +1,9 @@ +include(RunCTest) + +run_ctest(dirNotExist) +run_ctest(buildAndTestNoBuildDir + --build-and-test + ${RunCMake_BINARY_DIR}/buildAndTestNoBuildDir + ${RunCMake_BINARY_DIR}/buildAndTestNoBuildDir/CMakeLists.txt # Deliberately a file + --build-generator "${RunCMake_GENERATOR}" +) diff --git a/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-check.cmake b/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-check.cmake new file mode 100644 index 0000000..fcfe461 --- /dev/null +++ b/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-check.cmake @@ -0,0 +1,3 @@ +if(EXISTS ${RunCMake_TEST_BINARY_DIR}/CMakeCache.txt) + set(RunCMake_TEST_FAILED "Default build dir ${RunCMake_TEST_BINARY_DIR} was used, should not have been") +endif() diff --git a/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-result.txt b/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-result.txt new file mode 100644 index 0000000..0617a38 --- /dev/null +++ b/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-result.txt @@ -0,0 +1 @@ +^[^0][0-9]*$ diff --git a/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-stdout.txt b/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-stdout.txt new file mode 100644 index 0000000..da89317 --- /dev/null +++ b/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-stdout.txt @@ -0,0 +1 @@ +Failed to change working directory to .*[/\\]buildAndTestNoBuildDir[/\\]CMakeLists.txt : diff --git a/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir.cmake b/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir.cmake new file mode 100644 index 0000000..ad795c4 --- /dev/null +++ b/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir.cmake @@ -0,0 +1,7 @@ +# We want a single test that always passes. We should never actually get to +# configure with this file, so we use a successful configure-build-test +# sequence to denote failure of the test case. +include(CTest) +add_test(NAME willPass + COMMAND ${CMAKE_COMMAND} -E touch someFile.txt +) diff --git a/Tests/RunCMake/WorkingDirectory/dirNotExist-result.txt b/Tests/RunCMake/WorkingDirectory/dirNotExist-result.txt new file mode 100644 index 0000000..b57e2de --- /dev/null +++ b/Tests/RunCMake/WorkingDirectory/dirNotExist-result.txt @@ -0,0 +1 @@ +(-1|255) diff --git a/Tests/RunCMake/WorkingDirectory/dirNotExist-stderr.txt b/Tests/RunCMake/WorkingDirectory/dirNotExist-stderr.txt new file mode 100644 index 0000000..3cea890 --- /dev/null +++ b/Tests/RunCMake/WorkingDirectory/dirNotExist-stderr.txt @@ -0,0 +1 @@ +Failed to change working directory to .*[/\\]dirNotExist-build[/\\]thisDirWillNotExist : diff --git a/Tests/RunCMake/WorkingDirectory/dirNotExist-stdout.txt b/Tests/RunCMake/WorkingDirectory/dirNotExist-stdout.txt new file mode 100644 index 0000000..58aa6e4 --- /dev/null +++ b/Tests/RunCMake/WorkingDirectory/dirNotExist-stdout.txt @@ -0,0 +1,10 @@ +Test project .*/Tests/RunCMake/WorkingDirectory/dirNotExist-build +.* +Start 1: dirNotExist +1/1 Test #1: dirNotExist +\.+\*\*\*Not Run +[0-9.]+ sec ++ +0% tests passed, 1 tests failed out of 1 ++ +Total Test time \(real\) = +[0-9.]+ sec ++ +The following tests FAILED: +.* +1 - dirNotExist \(Not Run\)$ diff --git a/Tests/RunCMake/WorkingDirectory/dirNotExist.cmake b/Tests/RunCMake/WorkingDirectory/dirNotExist.cmake new file mode 100644 index 0000000..642386e --- /dev/null +++ b/Tests/RunCMake/WorkingDirectory/dirNotExist.cmake @@ -0,0 +1,6 @@ +include(CTest) + +add_test(NAME dirNotExist + COMMAND ${CMAKE_COMMAND} -E touch someFile.txt + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/thisDirWillNotExist +) diff --git a/Tests/RunCMake/WorkingDirectory/test.cmake.in b/Tests/RunCMake/WorkingDirectory/test.cmake.in new file mode 100644 index 0000000..8eccd79 --- /dev/null +++ b/Tests/RunCMake/WorkingDirectory/test.cmake.in @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.11) + +set(CTEST_SITE "test-site") +set(CTEST_BUILD_NAME "test-build-name") +set(CTEST_SOURCE_DIRECTORY "@RunCMake_BINARY_DIR@/@CASE_NAME@") +set(CTEST_BINARY_DIRECTORY "@RunCMake_BINARY_DIR@/@CASE_NAME@-build") +set(CTEST_CMAKE_GENERATOR "@RunCMake_GENERATOR@") +set(CTEST_CMAKE_GENERATOR_PLATFORM "@RunCMake_GENERATOR_PLATFORM@") +set(CTEST_CMAKE_GENERATOR_TOOLSET "@RunCMake_GENERATOR_TOOLSET@") +set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}") + +ctest_start(Experimental) +ctest_configure() +ctest_build() +ctest_test() diff --git a/Tests/RunCMake/add_library/CMP0073-stdout.txt b/Tests/RunCMake/add_library/CMP0073-stdout.txt new file mode 100644 index 0000000..84645b8 --- /dev/null +++ b/Tests/RunCMake/add_library/CMP0073-stdout.txt @@ -0,0 +1,3 @@ +-- warn_LIB_DEPENDS='general;bar;' +-- old_LIB_DEPENDS='general;bar;' +-- new_LIB_DEPENDS='' diff --git a/Tests/RunCMake/add_library/CMP0073.cmake b/Tests/RunCMake/add_library/CMP0073.cmake new file mode 100644 index 0000000..b34f5dc --- /dev/null +++ b/Tests/RunCMake/add_library/CMP0073.cmake @@ -0,0 +1,18 @@ +enable_language(C) + +add_library(warn empty.c) +target_link_libraries(warn bar) +message(STATUS "warn_LIB_DEPENDS='${warn_LIB_DEPENDS}'") + +cmake_policy(SET CMP0073 OLD) +add_library(old empty.c) +target_link_libraries(old bar) +message(STATUS "old_LIB_DEPENDS='${old_LIB_DEPENDS}'") + +cmake_policy(SET CMP0073 NEW) +add_library(new empty.c) +target_link_libraries(new bar) +message(STATUS "new_LIB_DEPENDS='${new_LIB_DEPENDS}'") +if(DEFINED new_LIB_DEPENDS) + message(FATAL_ERROR "new_LIB_DEPENDS set but should not be") +endif() diff --git a/Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-stderr.txt b/Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-stderr.txt index cd6f1e0..1bcc114 100644 --- a/Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-stderr.txt +++ b/Tests/RunCMake/add_library/OBJECTwithNoSourcesButLinkObjects-stderr.txt @@ -1,5 +1,4 @@ -^CMake Error at OBJECTwithNoSourcesButLinkObjects.cmake:[0-9]+ \(target_link_libraries\): - Object library target \"TestObjectLibWithoutSources\" may not link to - anything. +^CMake Error at OBJECTwithNoSourcesButLinkObjects.cmake:[0-9]+ \(add_library\): + No SOURCES given to target: TestObjectLibWithoutSources Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/add_library/OBJECTwithOnlyObjectSources-stderr.txt b/Tests/RunCMake/add_library/OBJECTwithOnlyObjectSources-stderr.txt deleted file mode 100644 index 77a72f1..0000000 --- a/Tests/RunCMake/add_library/OBJECTwithOnlyObjectSources-stderr.txt +++ /dev/null @@ -1,16 +0,0 @@ -^CMake Error at OBJECTwithOnlyObjectSources.cmake:[0-9]+ \(add_library\): - OBJECT library \"TestObjectLibWithoutSources\" contains: - - [^ -]*test(\.cpp)?\.o(bj)? - - but may contain only sources that compile, header files, and other files - that would not affect linking of a normal library. -Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\) - - -CMake Error at OBJECTwithOnlyObjectSources.cmake:[0-9]+ \(add_library\): - Only executables and non-OBJECT libraries may reference target objects. -Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/add_library/RunCMakeTest.cmake b/Tests/RunCMake/add_library/RunCMakeTest.cmake index 0ba6216..dfadb8f 100644 --- a/Tests/RunCMake/add_library/RunCMakeTest.cmake +++ b/Tests/RunCMake/add_library/RunCMakeTest.cmake @@ -1,5 +1,7 @@ include(RunCMake) +run_cmake(CMP0073) + run_cmake(INTERFACEwithNoSources) run_cmake(OBJECTwithNoSources) run_cmake(STATICwithNoSources) diff --git a/Tests/RunCMake/add_library/empty.c b/Tests/RunCMake/add_library/empty.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/add_library/empty.c diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-result.txt b/Tests/RunCMake/export/ForbiddenToExportImportedProperties-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-result.txt +++ b/Tests/RunCMake/export/ForbiddenToExportImportedProperties-result.txt diff --git a/Tests/RunCMake/export/ForbiddenToExportImportedProperties-stderr.txt b/Tests/RunCMake/export/ForbiddenToExportImportedProperties-stderr.txt new file mode 100644 index 0000000..ab03943 --- /dev/null +++ b/Tests/RunCMake/export/ForbiddenToExportImportedProperties-stderr.txt @@ -0,0 +1,3 @@ +CMake Error in CMakeLists.txt: + Target \"foo\" contains property \"IMPORTED_FOOBAR\" in EXPORT_PROPERTIES but + IMPORTED_\* and INTERFACE_\* properties are reserved. diff --git a/Tests/RunCMake/export/ForbiddenToExportImportedProperties.cmake b/Tests/RunCMake/export/ForbiddenToExportImportedProperties.cmake new file mode 100644 index 0000000..9c8653d --- /dev/null +++ b/Tests/RunCMake/export/ForbiddenToExportImportedProperties.cmake @@ -0,0 +1,12 @@ +enable_language(CXX) +add_library(foo empty.cpp) +set_target_properties(foo PROPERTIES + IMPORTED_FOOBAR "Some other string" + EXPORT_PROPERTIES "IMPORTED_FOOBAR" +) +export(TARGETS foo FILE "${CMAKE_CURRENT_BINARY_DIR}/foo.cmake") +install(TARGETS foo EXPORT fooExport + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjLHS-result.txt b/Tests/RunCMake/export/ForbiddenToExportInterfaceProperties-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/ObjectLibrary/LinkObjLHS-result.txt +++ b/Tests/RunCMake/export/ForbiddenToExportInterfaceProperties-result.txt diff --git a/Tests/RunCMake/export/ForbiddenToExportInterfaceProperties-stderr.txt b/Tests/RunCMake/export/ForbiddenToExportInterfaceProperties-stderr.txt new file mode 100644 index 0000000..577602b --- /dev/null +++ b/Tests/RunCMake/export/ForbiddenToExportInterfaceProperties-stderr.txt @@ -0,0 +1,3 @@ +CMake Error in CMakeLists.txt: + Target \"foo\" contains property \"INTERFACE_FOOBAR\" in EXPORT_PROPERTIES but + IMPORTED_\* and INTERFACE_\* properties are reserved. diff --git a/Tests/RunCMake/export/ForbiddenToExportInterfaceProperties.cmake b/Tests/RunCMake/export/ForbiddenToExportInterfaceProperties.cmake new file mode 100644 index 0000000..bab8de0 --- /dev/null +++ b/Tests/RunCMake/export/ForbiddenToExportInterfaceProperties.cmake @@ -0,0 +1,12 @@ +enable_language(CXX) +add_library(foo empty.cpp) +set_target_properties(foo PROPERTIES + INTERFACE_FOOBAR "Some string" + EXPORT_PROPERTIES "INTERFACE_FOOBAR" +) +export(TARGETS foo FILE "${CMAKE_CURRENT_BINARY_DIR}/foo.cmake") +install(TARGETS foo EXPORT fooExport + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) diff --git a/Tests/RunCMake/ObjectLibrary/ExportNotSupported-result.txt b/Tests/RunCMake/export/ForbiddenToExportPropertyWithGenExp-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/ObjectLibrary/ExportNotSupported-result.txt +++ b/Tests/RunCMake/export/ForbiddenToExportPropertyWithGenExp-result.txt diff --git a/Tests/RunCMake/export/ForbiddenToExportPropertyWithGenExp-stderr.txt b/Tests/RunCMake/export/ForbiddenToExportPropertyWithGenExp-stderr.txt new file mode 100644 index 0000000..56488e6 --- /dev/null +++ b/Tests/RunCMake/export/ForbiddenToExportPropertyWithGenExp-stderr.txt @@ -0,0 +1,3 @@ +CMake Error in CMakeLists.txt: + Target \"foo\" contains property \"JUST_A_PROPERTY\" in EXPORT_PROPERTIES but + this property contains a generator expression. This is not allowed. diff --git a/Tests/RunCMake/export/ForbiddenToExportPropertyWithGenExp.cmake b/Tests/RunCMake/export/ForbiddenToExportPropertyWithGenExp.cmake new file mode 100644 index 0000000..065cdbc --- /dev/null +++ b/Tests/RunCMake/export/ForbiddenToExportPropertyWithGenExp.cmake @@ -0,0 +1,12 @@ +enable_language(CXX) +add_library(foo empty.cpp) +set_target_properties(foo PROPERTIES + JUST_A_PROPERTY "$<C_COMPILER_VERSION:0>" + EXPORT_PROPERTIES "JUST_A_PROPERTY" +) +export(TARGETS foo FILE "${CMAKE_CURRENT_BINARY_DIR}/foo.cmake") +install(TARGETS foo EXPORT fooExport + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) diff --git a/Tests/RunCMake/export/RunCMakeTest.cmake b/Tests/RunCMake/export/RunCMakeTest.cmake index 6d0b7ca..10ced90 100644 --- a/Tests/RunCMake/export/RunCMakeTest.cmake +++ b/Tests/RunCMake/export/RunCMakeTest.cmake @@ -5,3 +5,6 @@ run_cmake(TargetNotFound) run_cmake(AppendExport) run_cmake(OldIface) run_cmake(NoExportSet) +run_cmake(ForbiddenToExportInterfaceProperties) +run_cmake(ForbiddenToExportImportedProperties) +run_cmake(ForbiddenToExportPropertyWithGenExp) diff --git a/Tests/RunCMake/export/empty.cpp b/Tests/RunCMake/export/empty.cpp new file mode 100644 index 0000000..11ec041 --- /dev/null +++ b/Tests/RunCMake/export/empty.cpp @@ -0,0 +1,7 @@ +#ifdef _WIN32 +__declspec(dllexport) +#endif + int empty() +{ + return 0; +} diff --git a/Tests/RunCMake/ObjectLibrary/BadObjSource2-result.txt b/Tests/RunCMake/file/GLOB-error-FOLLOW_SYMLINKS-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/ObjectLibrary/BadObjSource2-result.txt +++ b/Tests/RunCMake/file/GLOB-error-FOLLOW_SYMLINKS-result.txt diff --git a/Tests/RunCMake/file/GLOB-error-FOLLOW_SYMLINKS-stderr.txt b/Tests/RunCMake/file/GLOB-error-FOLLOW_SYMLINKS-stderr.txt new file mode 100644 index 0000000..af3cb2e --- /dev/null +++ b/Tests/RunCMake/file/GLOB-error-FOLLOW_SYMLINKS-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at GLOB-error-FOLLOW_SYMLINKS\.cmake:[0-9]+ \(file\): + file FOLLOW_SYMLINKS is not a valid parameter for GLOB\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/GLOB-error-FOLLOW_SYMLINKS.cmake b/Tests/RunCMake/file/GLOB-error-FOLLOW_SYMLINKS.cmake new file mode 100644 index 0000000..6d467a0 --- /dev/null +++ b/Tests/RunCMake/file/GLOB-error-FOLLOW_SYMLINKS.cmake @@ -0,0 +1 @@ +file(GLOB CONTENT_LIST FOLLOW_SYMLINKS) diff --git a/Tests/RunCMake/file/GLOB-error-RELATIVE-no-arg-result.txt b/Tests/RunCMake/file/GLOB-error-RELATIVE-no-arg-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file/GLOB-error-RELATIVE-no-arg-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file/GLOB-error-RELATIVE-no-arg-stderr.txt b/Tests/RunCMake/file/GLOB-error-RELATIVE-no-arg-stderr.txt new file mode 100644 index 0000000..30cec89 --- /dev/null +++ b/Tests/RunCMake/file/GLOB-error-RELATIVE-no-arg-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at GLOB-error-RELATIVE-no-arg\.cmake:[0-9]+ \(file\): + file GLOB requires a directory after the RELATIVE tag\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/GLOB-error-RELATIVE-no-arg.cmake b/Tests/RunCMake/file/GLOB-error-RELATIVE-no-arg.cmake new file mode 100644 index 0000000..a555881 --- /dev/null +++ b/Tests/RunCMake/file/GLOB-error-RELATIVE-no-arg.cmake @@ -0,0 +1 @@ +file(GLOB CONTENT_LIST RELATIVE) diff --git a/Tests/RunCMake/file/GLOB-noexp-LIST_DIRECTORIES-result.txt b/Tests/RunCMake/file/GLOB-noexp-LIST_DIRECTORIES-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file/GLOB-noexp-LIST_DIRECTORIES-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file/GLOB-noexp-LIST_DIRECTORIES-stderr.txt b/Tests/RunCMake/file/GLOB-noexp-LIST_DIRECTORIES-stderr.txt new file mode 100644 index 0000000..ee6cb0b --- /dev/null +++ b/Tests/RunCMake/file/GLOB-noexp-LIST_DIRECTORIES-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at GLOB-noexp-LIST_DIRECTORIES\.cmake:[0-9]+ \(file\): + file GLOB requires a glob expression after the bool\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/GLOB-noexp-RELATIVE-result.txt b/Tests/RunCMake/file/GLOB-noexp-RELATIVE-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file/GLOB-noexp-RELATIVE-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file/GLOB-noexp-RELATIVE-stderr.txt b/Tests/RunCMake/file/GLOB-noexp-RELATIVE-stderr.txt new file mode 100644 index 0000000..9c66631 --- /dev/null +++ b/Tests/RunCMake/file/GLOB-noexp-RELATIVE-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at GLOB-noexp-RELATIVE\.cmake:[0-9]+ \(file\): + file GLOB requires a glob expression after the directory\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/GLOB-noexp-RELATIVE.cmake b/Tests/RunCMake/file/GLOB-noexp-RELATIVE.cmake new file mode 100644 index 0000000..7b2d404 --- /dev/null +++ b/Tests/RunCMake/file/GLOB-noexp-RELATIVE.cmake @@ -0,0 +1 @@ +file(GLOB CONTENT_LIST RELATIVE "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/Tests/RunCMake/file/GLOB-sort-dedup-stderr.txt b/Tests/RunCMake/file/GLOB-sort-dedup-stderr.txt new file mode 100644 index 0000000..d2565e4 --- /dev/null +++ b/Tests/RunCMake/file/GLOB-sort-dedup-stderr.txt @@ -0,0 +1,2 @@ +content: 7[ ] +1aAb/\.hide;1aAb/1\.log;1aAb/1\.txt;1aAb/xkcd\.txt;a/1\.log;a/1\.txt;a/boot\.ini diff --git a/Tests/RunCMake/file/GLOB-sort-dedup.cmake b/Tests/RunCMake/file/GLOB-sort-dedup.cmake new file mode 100644 index 0000000..1e1c579 --- /dev/null +++ b/Tests/RunCMake/file/GLOB-sort-dedup.cmake @@ -0,0 +1,21 @@ +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test/a") +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test/1aAb") + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/a/1.log" "") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/a/1.txt" "") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/a/boot.ini" "") + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/1aAb/.hide" "") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/1aAb/1.txt" "") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/1aAb/1.log" "") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/1aAb/xkcd.txt" "") + +file(GLOB CONTENT_LIST + LIST_DIRECTORIES false + RELATIVE "${CMAKE_CURRENT_BINARY_DIR}/test" + "${CMAKE_CURRENT_BINARY_DIR}/test/a/*" + "${CMAKE_CURRENT_BINARY_DIR}/test/*/*" + ) +list(LENGTH CONTENT_LIST CONTENT_COUNT) +message("content: ${CONTENT_COUNT} ") +message("${CONTENT_LIST}") diff --git a/Tests/RunCMake/file/GLOB_RECURSE-noexp-FOLLOW_SYMLINKS-result.txt b/Tests/RunCMake/file/GLOB_RECURSE-noexp-FOLLOW_SYMLINKS-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file/GLOB_RECURSE-noexp-FOLLOW_SYMLINKS-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file/GLOB_RECURSE-noexp-FOLLOW_SYMLINKS-stderr.txt b/Tests/RunCMake/file/GLOB_RECURSE-noexp-FOLLOW_SYMLINKS-stderr.txt new file mode 100644 index 0000000..d0b2bff --- /dev/null +++ b/Tests/RunCMake/file/GLOB_RECURSE-noexp-FOLLOW_SYMLINKS-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at GLOB_RECURSE-noexp-FOLLOW_SYMLINKS\.cmake:[0-9]+ \(file\): + file GLOB_RECURSE requires a glob expression after FOLLOW_SYMLINKS\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/GLOB_RECURSE-noexp-FOLLOW_SYMLINKS.cmake b/Tests/RunCMake/file/GLOB_RECURSE-noexp-FOLLOW_SYMLINKS.cmake new file mode 100644 index 0000000..5e5ce92 --- /dev/null +++ b/Tests/RunCMake/file/GLOB_RECURSE-noexp-FOLLOW_SYMLINKS.cmake @@ -0,0 +1 @@ +file(GLOB_RECURSE CONTENT_LIST FOLLOW_SYMLINKS) diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake index 3be4fb7..4aab32d 100644 --- a/Tests/RunCMake/file/RunCMakeTest.cmake +++ b/Tests/RunCMake/file/RunCMakeTest.cmake @@ -5,6 +5,9 @@ run_cmake(DOWNLOAD-unused-argument) run_cmake(DOWNLOAD-httpheader-not-set) run_cmake(DOWNLOAD-netrc-bad) run_cmake(DOWNLOAD-pass-not-set) +run_cmake(TOUCH) +run_cmake(TOUCH-error-in-source-directory) +run_cmake(TOUCH-error-missing-directory) run_cmake(UPLOAD-unused-argument) run_cmake(UPLOAD-httpheader-not-set) run_cmake(UPLOAD-netrc-bad) @@ -32,11 +35,16 @@ run_cmake(LOCK-lowercase) run_cmake(READ_ELF) run_cmake(GLOB) run_cmake(GLOB_RECURSE) -# test is valid both for GLOB and GLOB_RECURSE +run_cmake(GLOB_RECURSE-noexp-FOLLOW_SYMLINKS) + +# tests are valid both for GLOB and GLOB_RECURSE +run_cmake(GLOB-sort-dedup) +run_cmake(GLOB-error-FOLLOW_SYMLINKS) run_cmake(GLOB-error-LIST_DIRECTORIES-not-boolean) -# test is valid both for GLOB and GLOB_RECURSE run_cmake(GLOB-error-LIST_DIRECTORIES-no-arg) +run_cmake(GLOB-error-RELATIVE-no-arg) run_cmake(GLOB-noexp-LIST_DIRECTORIES) +run_cmake(GLOB-noexp-RELATIVE) if(NOT WIN32 OR CYGWIN) run_cmake(GLOB_RECURSE-cyclic-recursion) diff --git a/Tests/RunCMake/file/TOUCH-error-in-source-directory-result.txt b/Tests/RunCMake/file/TOUCH-error-in-source-directory-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file/TOUCH-error-in-source-directory-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file/TOUCH-error-in-source-directory-stderr.txt b/Tests/RunCMake/file/TOUCH-error-in-source-directory-stderr.txt new file mode 100644 index 0000000..f899c75 --- /dev/null +++ b/Tests/RunCMake/file/TOUCH-error-in-source-directory-stderr.txt @@ -0,0 +1 @@ +.*file attempted to touch a file: diff --git a/Tests/RunCMake/file/TOUCH-error-in-source-directory.cmake b/Tests/RunCMake/file/TOUCH-error-in-source-directory.cmake new file mode 100644 index 0000000..9aa7c56 --- /dev/null +++ b/Tests/RunCMake/file/TOUCH-error-in-source-directory.cmake @@ -0,0 +1,2 @@ +set(CMAKE_DISABLE_SOURCE_CHANGES ON) +file(TOUCH "${CMAKE_CURRENT_SOURCE_DIR}/touch_test") diff --git a/Tests/RunCMake/file/TOUCH-error-missing-directory-result.txt b/Tests/RunCMake/file/TOUCH-error-missing-directory-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file/TOUCH-error-missing-directory-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file/TOUCH-error-missing-directory-stderr.txt b/Tests/RunCMake/file/TOUCH-error-missing-directory-stderr.txt new file mode 100644 index 0000000..f52e11a --- /dev/null +++ b/Tests/RunCMake/file/TOUCH-error-missing-directory-stderr.txt @@ -0,0 +1 @@ +.*file problem touching file: diff --git a/Tests/RunCMake/file/TOUCH-error-missing-directory.cmake b/Tests/RunCMake/file/TOUCH-error-missing-directory.cmake new file mode 100644 index 0000000..0cfb8d9 --- /dev/null +++ b/Tests/RunCMake/file/TOUCH-error-missing-directory.cmake @@ -0,0 +1 @@ +file(TOUCH "${CMAKE_CURRENT_BINARY_DIR}/missing/directory/file.to-touch") diff --git a/Tests/RunCMake/file/TOUCH-result.txt b/Tests/RunCMake/file/TOUCH-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file/TOUCH-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file/TOUCH-stderr.txt b/Tests/RunCMake/file/TOUCH-stderr.txt new file mode 100644 index 0000000..9f31676 --- /dev/null +++ b/Tests/RunCMake/file/TOUCH-stderr.txt @@ -0,0 +1,9 @@ +^CMake Error at TOUCH\.cmake:[0-9]+ \(file\): + file must be called with at least two arguments\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) ++ +CMake Error at TOUCH\.cmake:[0-9]+ \(file\): + file must be called with at least two arguments\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/file/TOUCH.cmake b/Tests/RunCMake/file/TOUCH.cmake new file mode 100644 index 0000000..8931eb5 --- /dev/null +++ b/Tests/RunCMake/file/TOUCH.cmake @@ -0,0 +1,16 @@ +set(file "${CMAKE_CURRENT_BINARY_DIR}/file-to-touch") + +file(REMOVE "${file}") +file(TOUCH_NOCREATE "${file}") +if(EXISTS "${file}") + message(FATAL_ERROR "error: TOUCH_NOCREATE created a file!") +endif() + +file(TOUCH "${file}") +if(NOT EXISTS "${file}") + message(FATAL_ERROR "error: TOUCH did not create a file!") +endif() +file(REMOVE "${file}") + +file(TOUCH) +file(TOUCH_NOCREATE) diff --git a/Tests/RunCMake/find_package/CMP0074-OLD-stderr.txt b/Tests/RunCMake/find_package/CMP0074-OLD-stderr.txt new file mode 100644 index 0000000..4c2e517 --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0074-OLD-stderr.txt @@ -0,0 +1,12 @@ +---------- +Foo_ROOT :<base>/foo/cmake_root +ENV{Foo_ROOT} :<base>/foo/env_root + +find_package\(Foo\) +FOO_TEST_FILE_FOO :FOO_TEST_FILE_FOO-NOTFOUND +FOO_TEST_FILE_ZOT :FOO_TEST_FILE_ZOT-NOTFOUND +FOO_TEST_PATH_FOO :FOO_TEST_PATH_FOO-NOTFOUND +FOO_TEST_PATH_ZOT :FOO_TEST_PATH_ZOT-NOTFOUND +FOO_TEST_PROG_FOO :FOO_TEST_PROG_FOO-NOTFOUND + +---------- diff --git a/Tests/RunCMake/find_package/CMP0074-OLD.cmake b/Tests/RunCMake/find_package/CMP0074-OLD.cmake new file mode 100644 index 0000000..4358317 --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0074-OLD.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0074 OLD) +include(CMP0074-common.cmake) diff --git a/Tests/RunCMake/find_package/CMP0074-WARN-stderr.txt b/Tests/RunCMake/find_package/CMP0074-WARN-stderr.txt new file mode 100644 index 0000000..c762d92 --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0074-WARN-stderr.txt @@ -0,0 +1,28 @@ +---------- +Foo_ROOT :<base>/foo/cmake_root +ENV{Foo_ROOT} :<base>/foo/env_root ++ +CMake Warning \(dev\) at CMP0074-common.cmake:[0-9]+ \(find_package\): + Policy CMP0074 is not set: find_package uses PackageName_ROOT variables. + Run "cmake --help-policy CMP0074" for policy details. Use the cmake_policy + command to set the policy and suppress this warning. + + CMake variable Foo_ROOT is set. + + Environment variable Foo_ROOT is set. + + For compatibility, CMake is ignoring the variable. +Call Stack \(most recent call first\): + CMP0074-common.cmake:[0-9]+ \(RunPackageRootTest\) + CMP0074-WARN.cmake:[0-9]+ \(include\) + CMakeLists.txt:[0-9]+ \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. ++ +find_package\(Foo\) +FOO_TEST_FILE_FOO :FOO_TEST_FILE_FOO-NOTFOUND +FOO_TEST_FILE_ZOT :FOO_TEST_FILE_ZOT-NOTFOUND +FOO_TEST_PATH_FOO :FOO_TEST_PATH_FOO-NOTFOUND +FOO_TEST_PATH_ZOT :FOO_TEST_PATH_ZOT-NOTFOUND +FOO_TEST_PROG_FOO :FOO_TEST_PROG_FOO-NOTFOUND + +---------- diff --git a/Tests/RunCMake/find_package/CMP0074-WARN.cmake b/Tests/RunCMake/find_package/CMP0074-WARN.cmake new file mode 100644 index 0000000..0d4ada7 --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0074-WARN.cmake @@ -0,0 +1,2 @@ +# (do not set CMP0074) +include(CMP0074-common.cmake) diff --git a/Tests/RunCMake/find_package/CMP0074-common.cmake b/Tests/RunCMake/find_package/CMP0074-common.cmake new file mode 100644 index 0000000..bfacd82 --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0074-common.cmake @@ -0,0 +1,46 @@ +# (includer selects CMP0074) +cmake_policy(SET CMP0057 NEW) +list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot) +set(PackageRoot_BASE ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot) + +function(PrintPath label path) + string(REPLACE "${PackageRoot_BASE}" "<base>" out "${path}") + message("${label}${out}") +endfunction() + +macro(CleanUpPackageRootTest) + unset(Foo_ROOT) + unset(ENV{Foo_ROOT}) + unset(FOO_TEST_FILE_FOO) + unset(FOO_TEST_FILE_ZOT) + unset(FOO_TEST_PATH_FOO) + unset(FOO_TEST_PATH_ZOT) + unset(FOO_TEST_PROG_FOO) + unset(FOO_TEST_FILE_FOO CACHE) + unset(FOO_TEST_FILE_ZOT CACHE) + unset(FOO_TEST_PATH_FOO CACHE) + unset(FOO_TEST_PATH_ZOT CACHE) + unset(FOO_TEST_PROG_FOO CACHE) +endmacro() + +macro(RunPackageRootTest) + message("----------") + PrintPath("Foo_ROOT :" "${Foo_ROOT}") + PrintPath("ENV{Foo_ROOT} :" "$ENV{Foo_ROOT}") + message("") + + find_package(Foo) + message("find_package(Foo)") + PrintPath("FOO_TEST_FILE_FOO :" "${FOO_TEST_FILE_FOO}") + PrintPath("FOO_TEST_FILE_ZOT :" "${FOO_TEST_FILE_ZOT}") + PrintPath("FOO_TEST_PATH_FOO :" "${FOO_TEST_PATH_FOO}") + PrintPath("FOO_TEST_PATH_ZOT :" "${FOO_TEST_PATH_ZOT}") + PrintPath("FOO_TEST_PROG_FOO :" "${FOO_TEST_PROG_FOO}") + CleanUpPackageRootTest() + message("") +endmacro() + +set(Foo_ROOT ${PackageRoot_BASE}/foo/cmake_root) +set(ENV{Foo_ROOT} ${PackageRoot_BASE}/foo/env_root) +RunPackageRootTest() +message("----------") diff --git a/Tests/RunCMake/find_package/PackageRoot.cmake b/Tests/RunCMake/find_package/PackageRoot.cmake index 4c4f4c2..aa12e9b 100644 --- a/Tests/RunCMake/find_package/PackageRoot.cmake +++ b/Tests/RunCMake/find_package/PackageRoot.cmake @@ -1,5 +1,5 @@ -set(__UNDOCUMENTED_CMAKE_FIND_PACKAGE_ROOT 1) cmake_policy(SET CMP0057 NEW) +cmake_policy(SET CMP0074 NEW) list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot) set(PackageRoot_BASE ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot) diff --git a/Tests/RunCMake/find_package/PackageRootNestedConfig.cmake b/Tests/RunCMake/find_package/PackageRootNestedConfig.cmake index ba06c09..1ef32cb 100644 --- a/Tests/RunCMake/find_package/PackageRootNestedConfig.cmake +++ b/Tests/RunCMake/find_package/PackageRootNestedConfig.cmake @@ -1,5 +1,5 @@ -set(__UNDOCUMENTED_CMAKE_FIND_PACKAGE_ROOT 1) cmake_policy(SET CMP0057 NEW) +cmake_policy(SET CMP0074 NEW) list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot) set(PackageRoot_BASE ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot) diff --git a/Tests/RunCMake/find_package/PackageRootNestedModule.cmake b/Tests/RunCMake/find_package/PackageRootNestedModule.cmake index 2795cd4..017834c 100644 --- a/Tests/RunCMake/find_package/PackageRootNestedModule.cmake +++ b/Tests/RunCMake/find_package/PackageRootNestedModule.cmake @@ -1,5 +1,5 @@ -set(__UNDOCUMENTED_CMAKE_FIND_PACKAGE_ROOT 1) cmake_policy(SET CMP0057 NEW) +cmake_policy(SET CMP0074 NEW) list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot) set(PackageRoot_BASE ${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot) diff --git a/Tests/RunCMake/find_package/RunCMakeTest.cmake b/Tests/RunCMake/find_package/RunCMakeTest.cmake index d548da0..c068402 100644 --- a/Tests/RunCMake/find_package/RunCMakeTest.cmake +++ b/Tests/RunCMake/find_package/RunCMakeTest.cmake @@ -1,5 +1,7 @@ include(RunCMake) +run_cmake(CMP0074-WARN) +run_cmake(CMP0074-OLD) run_cmake(ComponentRequiredAndOptional) run_cmake(MissingNormal) run_cmake(MissingNormalRequired) diff --git a/Tests/RunCMake/get_property/directory_properties-stderr.txt b/Tests/RunCMake/get_property/directory_properties-stderr.txt index 6d5bcdb..89f5618 100644 --- a/Tests/RunCMake/get_property/directory_properties-stderr.txt +++ b/Tests/RunCMake/get_property/directory_properties-stderr.txt @@ -19,4 +19,12 @@ get_property: -->[^<;]*/Tests/RunCMake/get_property<-- get_directory_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties-build/directory_properties<-- get_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties-build/directory_properties<-- get_directory_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties<-- -get_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties<--$ +get_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties<-- +get_directory_property: --><-- +get_property: --><-- +get_directory_property: -->test1;test2<-- +get_property: -->test1;test2<-- +get_directory_property: -->test1;test2;test3<-- +get_property: -->test1;test2;test3<-- +get_directory_property: -->Sub/test1;Sub/test2<-- +get_property: -->Sub/test1;Sub/test2<--$ diff --git a/Tests/RunCMake/get_property/directory_properties.cmake b/Tests/RunCMake/get_property/directory_properties.cmake index 4e68738..9b978fd 100644 --- a/Tests/RunCMake/get_property/directory_properties.cmake +++ b/Tests/RunCMake/get_property/directory_properties.cmake @@ -28,3 +28,12 @@ check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" BINARY_DIR) check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" SOURCE_DIR) check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}/directory_properties" BINARY_DIR) check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}/directory_properties" SOURCE_DIR) + +check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" TESTS) +add_test(NAME test1 COMMAND "${CMAKE_COMMAND}" -E echo "test1") +add_test(NAME test2 COMMAND "${CMAKE_COMMAND}" -E echo "test2") +check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" TESTS) +add_test(NAME test3 COMMAND "${CMAKE_COMMAND}" -E echo "test3") +check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" TESTS) + +check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}/directory_properties" TESTS) diff --git a/Tests/RunCMake/get_property/directory_properties/CMakeLists.txt b/Tests/RunCMake/get_property/directory_properties/CMakeLists.txt index 7318b97..95106ad 100644 --- a/Tests/RunCMake/get_property/directory_properties/CMakeLists.txt +++ b/Tests/RunCMake/get_property/directory_properties/CMakeLists.txt @@ -4,3 +4,6 @@ subdirs(sub2) add_custom_target(CustomSub) add_library(InterfaceSub INTERFACE) add_library(my::InterfaceSub ALIAS InterfaceSub) + +add_test(Sub/test1 COMMAND "${CMAKE_COMMAND}" -E echo "Sub/test1") +add_test(Sub/test2 COMMAND "${CMAKE_COMMAND}" -E echo "Sub/test2") diff --git a/Tests/RunCMake/project/LanguagesUnordered-stderr.txt b/Tests/RunCMake/project/LanguagesUnordered-stderr.txt new file mode 100644 index 0000000..5108670 --- /dev/null +++ b/Tests/RunCMake/project/LanguagesUnordered-stderr.txt @@ -0,0 +1 @@ + the following parameters must be specified after LANGUAGES keyword: C. diff --git a/Tests/RunCMake/project/LanguagesUnordered.cmake b/Tests/RunCMake/project/LanguagesUnordered.cmake new file mode 100644 index 0000000..cd3ba28 --- /dev/null +++ b/Tests/RunCMake/project/LanguagesUnordered.cmake @@ -0,0 +1 @@ +project(ProjectA C LANGUAGES CXX) diff --git a/Tests/RunCMake/project/ProjectDescriptionNoArg-stderr.txt b/Tests/RunCMake/project/ProjectDescriptionNoArg-stderr.txt new file mode 100644 index 0000000..910106f --- /dev/null +++ b/Tests/RunCMake/project/ProjectDescriptionNoArg-stderr.txt @@ -0,0 +1,2 @@ + DESCRIPTION keyword not followed by a value or was followed by a value that + expanded to nothing. diff --git a/Tests/RunCMake/project/ProjectDescriptionNoArg.cmake b/Tests/RunCMake/project/ProjectDescriptionNoArg.cmake new file mode 100644 index 0000000..25acff8 --- /dev/null +++ b/Tests/RunCMake/project/ProjectDescriptionNoArg.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0048 NEW) +project(ProjectDescriptionTest VERSION 1.0.0 LANGUAGES NONE DESCRIPTION) diff --git a/Tests/RunCMake/project/ProjectDescriptionNoArg2-stderr.txt b/Tests/RunCMake/project/ProjectDescriptionNoArg2-stderr.txt new file mode 100644 index 0000000..910106f --- /dev/null +++ b/Tests/RunCMake/project/ProjectDescriptionNoArg2-stderr.txt @@ -0,0 +1,2 @@ + DESCRIPTION keyword not followed by a value or was followed by a value that + expanded to nothing. diff --git a/Tests/RunCMake/project/ProjectDescriptionNoArg2.cmake b/Tests/RunCMake/project/ProjectDescriptionNoArg2.cmake new file mode 100644 index 0000000..f50a2f6 --- /dev/null +++ b/Tests/RunCMake/project/ProjectDescriptionNoArg2.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0048 NEW) +project(ProjectDescriptionTest VERSION 1.0.0 DESCRIPTION LANGUAGES NONE) diff --git a/Tests/RunCMake/project/ProjectHomepage-stdout.txt b/Tests/RunCMake/project/ProjectHomepage-stdout.txt new file mode 100644 index 0000000..253990f --- /dev/null +++ b/Tests/RunCMake/project/ProjectHomepage-stdout.txt @@ -0,0 +1,3 @@ +-- PROJECT_HOMEPAGE_URL=http://example.com +-- CMAKE_PROJECT_HOMEPAGE_URL=http://example.com +-- ProjectHomepageTest_HOMEPAGE_URL=http://example.com diff --git a/Tests/RunCMake/project/ProjectHomepage.cmake b/Tests/RunCMake/project/ProjectHomepage.cmake new file mode 100644 index 0000000..3307f1f --- /dev/null +++ b/Tests/RunCMake/project/ProjectHomepage.cmake @@ -0,0 +1,14 @@ +cmake_policy(SET CMP0048 NEW) +project(ProjectHomepageTest VERSION 1.0.0 HOMEPAGE_URL "http://example.com" LANGUAGES) +if(NOT PROJECT_HOMEPAGE_URL) + message(FATAL_ERROR "PROJECT_HOMEPAGE_URL expected to be set") +endif() +if(NOT CMAKE_PROJECT_HOMEPAGE_URL) + message(FATAL_ERROR "CMAKE_PROJECT_HOMEPAGE_URL expected to be set") +endif() +if(NOT ProjectHomepageTest_HOMEPAGE_URL) + message(FATAL_ERROR "ProjectHomepageTest_HOMEPAGE_URL expected to be set") +endif() +message(STATUS "PROJECT_HOMEPAGE_URL=${PROJECT_HOMEPAGE_URL}") +message(STATUS "CMAKE_PROJECT_HOMEPAGE_URL=${CMAKE_PROJECT_HOMEPAGE_URL}") +message(STATUS "ProjectHomepageTest_HOMEPAGE_URL=${ProjectHomepageTest_HOMEPAGE_URL}") diff --git a/Tests/RunCMake/project/ProjectHomepage2-result.txt b/Tests/RunCMake/project/ProjectHomepage2-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/project/ProjectHomepage2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/project/ProjectHomepage2-stderr.txt b/Tests/RunCMake/project/ProjectHomepage2-stderr.txt new file mode 100644 index 0000000..4a0adc2 --- /dev/null +++ b/Tests/RunCMake/project/ProjectHomepage2-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at ProjectHomepage2.cmake:2 \(project\): + HOMEPAGE_URL may be specified at most once. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/project/ProjectHomepage2.cmake b/Tests/RunCMake/project/ProjectHomepage2.cmake new file mode 100644 index 0000000..184c392 --- /dev/null +++ b/Tests/RunCMake/project/ProjectHomepage2.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0048 NEW) +project(ProjectDescriptionTest VERSION 1.0.0 HOMEPAGE_URL "http://example.com" HOMEPAGE_URL "http://example.com" LANGUAGES) diff --git a/Tests/RunCMake/project/ProjectHomepageNoArg-stderr.txt b/Tests/RunCMake/project/ProjectHomepageNoArg-stderr.txt new file mode 100644 index 0000000..c9503b7 --- /dev/null +++ b/Tests/RunCMake/project/ProjectHomepageNoArg-stderr.txt @@ -0,0 +1,5 @@ +^CMake Warning at ProjectHomepageNoArg.cmake:2 \(project\): + HOMEPAGE_URL keyword not followed by a value or was followed by a value + that expanded to nothing. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/project/ProjectHomepageNoArg.cmake b/Tests/RunCMake/project/ProjectHomepageNoArg.cmake new file mode 100644 index 0000000..4605541 --- /dev/null +++ b/Tests/RunCMake/project/ProjectHomepageNoArg.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0048 NEW) +project(ProjectDescriptionTest VERSION 1.0.0 LANGUAGES NONE HOMEPAGE_URL) diff --git a/Tests/RunCMake/project/RunCMakeTest.cmake b/Tests/RunCMake/project/RunCMakeTest.cmake index 3d13e2e..e9fb929 100644 --- a/Tests/RunCMake/project/RunCMakeTest.cmake +++ b/Tests/RunCMake/project/RunCMakeTest.cmake @@ -7,8 +7,14 @@ run_cmake(LanguagesImplicit) run_cmake(LanguagesEmpty) run_cmake(LanguagesNONE) run_cmake(LanguagesTwice) +run_cmake(LanguagesUnordered) run_cmake(ProjectDescription) run_cmake(ProjectDescription2) +run_cmake(ProjectDescriptionNoArg) +run_cmake(ProjectDescriptionNoArg2) +run_cmake(ProjectHomepage) +run_cmake(ProjectHomepage2) +run_cmake(ProjectHomepageNoArg) run_cmake(VersionAndLanguagesEmpty) run_cmake(VersionEmpty) run_cmake(VersionInvalid) diff --git a/Tests/RunCMake/project/VersionMissingLanguages-stderr.txt b/Tests/RunCMake/project/VersionMissingLanguages-stderr.txt index 52433bc..576ac69 100644 --- a/Tests/RunCMake/project/VersionMissingLanguages-stderr.txt +++ b/Tests/RunCMake/project/VersionMissingLanguages-stderr.txt @@ -1,4 +1,5 @@ CMake Error at VersionMissingLanguages.cmake:2 \(project\): - project with VERSION must use LANGUAGES before language names. + project with VERSION, DESCRIPTION or HOMEPAGE_URL must use LANGUAGES before + language names. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/project/VersionMissingValueOkay-stderr.txt b/Tests/RunCMake/project/VersionMissingValueOkay-stderr.txt new file mode 100644 index 0000000..3228df7 --- /dev/null +++ b/Tests/RunCMake/project/VersionMissingValueOkay-stderr.txt @@ -0,0 +1,2 @@ + VERSION keyword not followed by a value or was followed by a value that + expanded to nothing. diff --git a/Tests/RunCMake/string/Join.cmake b/Tests/RunCMake/string/Join.cmake new file mode 100644 index 0000000..081f1e4 --- /dev/null +++ b/Tests/RunCMake/string/Join.cmake @@ -0,0 +1,16 @@ +string(JOIN % out) +if(NOT out STREQUAL "") + message(FATAL_ERROR "\"string(JOIN % out)\" set out to \"${out}\"") +endif() +string(JOIN % out a) +if(NOT out STREQUAL "a") + message(FATAL_ERROR "\"string(JOIN % out a)\" set out to \"${out}\"") +endif() +string(JOIN % out a "b") +if(NOT out STREQUAL "a%b") + message(FATAL_ERROR "\"string(JOIN % out a \"b\")\" set out to \"${out}\"") +endif() +string(JOIN :: out a "b") +if(NOT out STREQUAL "a::b") + message(FATAL_ERROR "\"string(JOIN :: out a \"b\")\" set out to \"${out}\"") +endif() diff --git a/Tests/RunCMake/string/JoinNoArgs-result.txt b/Tests/RunCMake/string/JoinNoArgs-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/string/JoinNoArgs-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/string/JoinNoArgs-stderr.txt b/Tests/RunCMake/string/JoinNoArgs-stderr.txt new file mode 100644 index 0000000..d9dcec3 --- /dev/null +++ b/Tests/RunCMake/string/JoinNoArgs-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at JoinNoArgs.cmake:1 \(string\): + string sub-command JOIN requires at least two arguments. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/string/JoinNoArgs.cmake b/Tests/RunCMake/string/JoinNoArgs.cmake new file mode 100644 index 0000000..35ba4d9 --- /dev/null +++ b/Tests/RunCMake/string/JoinNoArgs.cmake @@ -0,0 +1 @@ +string(JOIN) diff --git a/Tests/RunCMake/string/JoinNoVar-result.txt b/Tests/RunCMake/string/JoinNoVar-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/string/JoinNoVar-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/string/JoinNoVar-stderr.txt b/Tests/RunCMake/string/JoinNoVar-stderr.txt new file mode 100644 index 0000000..90701a9 --- /dev/null +++ b/Tests/RunCMake/string/JoinNoVar-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at JoinNoVar.cmake:1 \(string\): + string sub-command JOIN requires at least two arguments. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/string/JoinNoVar.cmake b/Tests/RunCMake/string/JoinNoVar.cmake new file mode 100644 index 0000000..35f7b92 --- /dev/null +++ b/Tests/RunCMake/string/JoinNoVar.cmake @@ -0,0 +1 @@ +string(JOIN ";") diff --git a/Tests/RunCMake/string/RunCMakeTest.cmake b/Tests/RunCMake/string/RunCMakeTest.cmake index 513d1e3..211337a 100644 --- a/Tests/RunCMake/string/RunCMakeTest.cmake +++ b/Tests/RunCMake/string/RunCMakeTest.cmake @@ -9,6 +9,10 @@ run_cmake(PrependNoArgs) run_cmake(Concat) run_cmake(ConcatNoArgs) +run_cmake(Join) +run_cmake(JoinNoArgs) +run_cmake(JoinNoVar) + run_cmake(Timestamp) run_cmake(TimestampEmpty) run_cmake(TimestampInvalid) diff --git a/Tests/SwigTest/runme.py b/Tests/SwigTest/runme.py deleted file mode 100644 index ed3909e..0000000 --- a/Tests/SwigTest/runme.py +++ /dev/null @@ -1,51 +0,0 @@ -# file: runme.py - -# This file illustrates the shadow-class C++ interface generated -# by SWIG. - -import example - -# ----- Object creation ----- - -print "Creating some objects:" -c = example.Circle(10) -print " Created circle", c -s = example.Square(10) -print " Created square", s - -# ----- Access a static member ----- - -print "\nA total of", example.cvar.Shape_nshapes,"shapes were created" - -# ----- Member data access ----- - -# Set the location of the object - -c.x = 20 -c.y = 30 - -s.x = -10 -s.y = 5 - -print "\nHere is their current position:" -print " Circle = (%f, %f)" % (c.x,c.y) -print " Square = (%f, %f)" % (s.x,s.y) - -# ----- Call some methods ----- - -print "\nHere are some properties of the shapes:" -for o in [c,s]: - print " ", o - print " area = ", o.area() - print " perimeter = ", o.perimeter() - -print "\nGuess I'll clean up now" - -# Note: this invokes the virtual destructor -del c -del s - -s = 3 -print example.cvar.Shape_nshapes,"shapes remain" -print "Goodbye" - diff --git a/Utilities/cmlibuv/include/uv.h b/Utilities/cmlibuv/include/uv.h index 328ce9e..875e30a 100644 --- a/Utilities/cmlibuv/include/uv.h +++ b/Utilities/cmlibuv/include/uv.h @@ -925,6 +925,19 @@ typedef struct uv_process_options_s { */ uv_uid_t uid; uv_gid_t gid; + /* + Libuv can set the child process' CPU affinity mask. This happens when + `cpumask` is non-NULL. It must point to an array of char values + of length `cpumask_size`, whose value must be at least that returned by + uv_cpumask_size(). Each byte in the mask can be either zero (false) + or non-zero (true) to indicate whether the corresponding processor at + that index is included. + + If enabled on an unsupported platform, uv_spawn() will fail with + UV_ENOTSUP. + */ + char* cpumask; + size_t cpumask_size; } uv_process_options_t; /* @@ -1094,6 +1107,7 @@ UV_EXTERN uv_pid_t uv_os_getppid(void); UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); +UV_EXTERN int uv_cpumask_size(void); UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses, int* count); diff --git a/Utilities/cmlibuv/src/unix/core.c b/Utilities/cmlibuv/src/unix/core.c index c7e431e..faaf697 100644 --- a/Utilities/cmlibuv/src/unix/core.c +++ b/Utilities/cmlibuv/src/unix/core.c @@ -40,6 +40,7 @@ #include <sys/uio.h> /* writev */ #include <sys/resource.h> /* getrusage */ #include <pwd.h> +#include <sched.h> #ifdef __sun # include <netdb.h> /* MAXHOSTNAMELEN on Solaris */ @@ -63,6 +64,8 @@ # include <sys/sysctl.h> # include <sys/filio.h> # include <sys/wait.h> +# include <sys/param.h> +# include <sys/cpuset.h> # define UV__O_CLOEXEC O_CLOEXEC # if defined(__FreeBSD__) && __FreeBSD__ >= 10 # define uv__accept4 accept4 @@ -1340,6 +1343,15 @@ int uv_os_gethostname(char* buffer, size_t* size) { } +int uv_cpumask_size(void) { +#if defined(__linux__) || defined(__FreeBSD__) + return CPU_SETSIZE; +#else + return UV_ENOTSUP; +#endif +} + + uv_os_fd_t uv_get_osfhandle(int fd) { return fd; } diff --git a/Utilities/cmlibuv/src/unix/process.c b/Utilities/cmlibuv/src/unix/process.c index 9842710..47ab1dc 100644 --- a/Utilities/cmlibuv/src/unix/process.c +++ b/Utilities/cmlibuv/src/unix/process.c @@ -32,6 +32,7 @@ #include <unistd.h> #include <fcntl.h> #include <poll.h> +#include <sched.h> #if defined(__APPLE__) && !TARGET_OS_IPHONE # include <crt_externs.h> @@ -44,6 +45,16 @@ extern char **environ; # include <grp.h> #endif +#ifndef CMAKE_BOOTSTRAP +#if defined(__linux__) +# define uv__cpu_set_t cpu_set_t +#elif defined(__FreeBSD__) +# include <sys/param.h> +# include <sys/cpuset.h> +# include <pthread_np.h> +# define uv__cpu_set_t cpuset_t +#endif +#endif static void uv__chld(uv_signal_t* handle, int signum) { uv_process_t* process; @@ -285,6 +296,14 @@ static void uv__process_child_init(const uv_process_options_t* options, int err; int fd; int n; +#ifndef CMAKE_BOOTSTRAP +#if defined(__linux__) || defined(__FreeBSD__) + int r; + int i; + int cpumask_size; + uv__cpu_set_t cpuset; +#endif +#endif if (options->flags & UV_PROCESS_DETACHED) setsid(); @@ -375,6 +394,28 @@ static void uv__process_child_init(const uv_process_options_t* options, _exit(127); } +#ifndef CMAKE_BOOTSTRAP +#if defined(__linux__) || defined(__FreeBSD__) + if (options->cpumask != NULL) { + cpumask_size = uv_cpumask_size(); + assert(options->cpumask_size >= (size_t)cpumask_size); + + CPU_ZERO(&cpuset); + for (i = 0; i < cpumask_size; ++i) { + if (options->cpumask[i]) { + CPU_SET(i, &cpuset); + } + } + + r = -pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset); + if (r != 0) { + uv__write_int(error_fd, r); + _exit(127); + } + } +#endif +#endif + if (options->env != NULL) { environ = options->env; } @@ -429,6 +470,20 @@ int uv_spawn(uv_loop_t* loop, int i; int status; + if (options->cpumask != NULL) { +#ifndef CMAKE_BOOTSTRAP +#if defined(__linux__) || defined(__FreeBSD__) + if (options->cpumask_size < (size_t)uv_cpumask_size()) { + return UV_EINVAL; + } +#else + return UV_ENOTSUP; +#endif +#else + return UV_ENOTSUP; +#endif + } + assert(options->file != NULL); assert(!(options->flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | diff --git a/Utilities/cmlibuv/src/win/core.c b/Utilities/cmlibuv/src/win/core.c index 9ed4e82..8d121b3 100644 --- a/Utilities/cmlibuv/src/win/core.c +++ b/Utilities/cmlibuv/src/win/core.c @@ -603,3 +603,7 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { return 0; } + +int uv_cpumask_size(void) { + return (int)(sizeof(DWORD_PTR) * 8); +} diff --git a/Utilities/cmlibuv/src/win/process.c b/Utilities/cmlibuv/src/win/process.c index cc06d9e..f5f05af 100644 --- a/Utilities/cmlibuv/src/win/process.c +++ b/Utilities/cmlibuv/src/win/process.c @@ -954,6 +954,12 @@ int uv_spawn(uv_loop_t* loop, return UV_EINVAL; } + if (options->cpumask != NULL) { + if (options->cpumask_size < (size_t)uv_cpumask_size()) { + return UV_EINVAL; + } + } + assert(options->file != NULL); assert(!(options->flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | @@ -1084,6 +1090,12 @@ int uv_spawn(uv_loop_t* loop, process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; } + if (options->cpumask != NULL) { + /* Create the child in a suspended state so we have a chance to set + its process affinity before it runs. */ + process_flags |= CREATE_SUSPENDED; + } + if (!CreateProcessW(application_path, arguments, NULL, @@ -1099,6 +1111,50 @@ int uv_spawn(uv_loop_t* loop, goto done; } + if (options->cpumask != NULL) { + /* The child is currently suspended. Set its process affinity + or terminate it if we can't. */ + int i; + int cpumasksize; + DWORD_PTR sysmask; + DWORD_PTR oldmask; + DWORD_PTR newmask; + + cpumasksize = uv_cpumask_size(); + + if (!GetProcessAffinityMask(info.hProcess, &oldmask, &sysmask)) { + err = GetLastError(); + TerminateProcess(info.hProcess, 1); + goto done; + } + + newmask = 0; + for (i = 0; i < cpumasksize; i++) { + if (options->cpumask[i]) { + if (oldmask & (((DWORD_PTR)1) << i)) { + newmask |= ((DWORD_PTR)1) << i; + } else { + err = UV_EINVAL; + TerminateProcess(info.hProcess, 1); + goto done; + } + } + } + + if (!SetProcessAffinityMask(info.hProcess, newmask)) { + err = GetLastError(); + TerminateProcess(info.hProcess, 1); + goto done; + } + + /* The process affinity of the child is set. Let it run. */ + if (ResumeThread(info.hThread) == ((DWORD)-1)) { + err = GetLastError(); + TerminateProcess(info.hProcess, 1); + goto done; + } + } + /* Spawn succeeded */ /* Beyond this point, failure is reported asynchronously. */ @@ -1116,8 +1116,10 @@ done rm -f "${TMPFILE}.cxx" if [ -z "${cmake_cxx_compiler}" ]; then -cmake_error 7 "Cannot find a C++ compiler supporting C++11 on this system. +cmake_error 7 "Cannot find a C++ compiler that supports both C++11 and the specified C++ flags. Please specify one using environment variable CXX. +The C++ flags are \"$cmake_cxx_flags\". +They can be changed using the environment variable CXXFLAGS. See cmake_bootstrap.log for compilers attempted." fi echo "C++ compiler on this system is: ${cmake_cxx_compiler} ${cmake_cxx_flags}" |