diff options
255 files changed, 3937 insertions, 816 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 08fc107..c811092 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -59,7 +59,7 @@ p:doc-package: - .cmake_doc_artifacts - .run_only_for_package -.u:source-package: +u:source-package: extends: - .rsync_upload_binary - .run_only_for_package @@ -77,7 +77,7 @@ b:help:master: - .cmake_org_help - .run_only_for_continuous_master -.u:help:master: +u:help:master: extends: - .rsync_upload_help - .run_only_for_continuous_master @@ -93,7 +93,7 @@ b:help:stage: - .cmake_org_help - .run_only_for_continuous_stage -.u:help:stage: +u:help:stage: extends: - .rsync_upload_help - .run_only_for_continuous_stage @@ -495,6 +495,27 @@ t:intel2021.2.0-makefiles: CMAKE_CI_BUILD_NAME: intel2021.2.0_makefiles CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2021.2.0-el8 +t:intel2021.3.0-makefiles: + extends: + - .cmake_test_linux_intelclassic_makefiles + variables: + CMAKE_CI_BUILD_NAME: intel2021.3.0_makefiles + CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2021.3.0-el8 + +t:intel2021.4.0-makefiles: + extends: + - .cmake_test_linux_intelclassic_makefiles + variables: + CMAKE_CI_BUILD_NAME: intel2021.4.0_makefiles + CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2021.4.0-el8 + +t:intel2021.5.0-makefiles: + extends: + - .cmake_test_linux_intelclassic_makefiles + variables: + CMAKE_CI_BUILD_NAME: intel2021.5.0_makefiles + CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2022.0.2-el8 + t:oneapi2021.1.1-makefiles: extends: - .cmake_test_linux_inteloneapi_makefiles @@ -516,6 +537,27 @@ t:oneapi2021.2.0-makefiles: CMAKE_CI_BUILD_NAME: oneapi2021.2.0_makefiles CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2021.2.0-el8 +t:oneapi2021.3.0-makefiles: + extends: + - .cmake_test_linux_inteloneapi_makefiles + variables: + CMAKE_CI_BUILD_NAME: oneapi2021.3.0_makefiles + CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2021.3.0-el8 + +t:oneapi2021.4.0-makefiles: + extends: + - .cmake_test_linux_inteloneapi_makefiles + variables: + CMAKE_CI_BUILD_NAME: oneapi2021.4.0_makefiles + CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2021.4.0-el8 + +t:oneapi2022.0.2-makefiles: + extends: + - .cmake_test_linux_inteloneapi_makefiles + variables: + CMAKE_CI_BUILD_NAME: oneapi2022.0.2_makefiles + CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2022.0.2-el8 + b:linux-x86_64-package: extends: - .linux_package @@ -529,7 +571,7 @@ b:linux-x86_64-package: needs: - p:doc-package -.u:linux-x86_64-package: +u:linux-x86_64-package: extends: - .rsync_upload_binary - .run_only_for_package @@ -553,7 +595,7 @@ b:linux-aarch64-package: needs: - p:doc-package -.u:linux-aarch64-package: +u:linux-aarch64-package: extends: - .rsync_upload_binary - .run_only_for_package @@ -694,7 +736,7 @@ b:macos-package: needs: - p:doc-package -.u:macos-package: +u:macos-package: extends: - .rsync_upload_binary - .run_only_for_package @@ -717,7 +759,7 @@ b:macos10.10-package: needs: - p:doc-package -.u:macos10.10-package: +u:macos10.10-package: extends: - .rsync_upload_binary - .run_only_for_package @@ -834,6 +876,66 @@ t:windows-borland5.8: variables: CMAKE_CI_JOB_NIGHTLY: "true" +t:windows-clang13.0-cl-ninja: + extends: + - .windows_clang_ninja + - .cmake_test_windows_clang + - .windows_tags_concurrent + - .cmake_junit_artifacts + - .run_dependent + dependencies: + - t:windows-vs2022-x64-ninja + needs: + - t:windows-vs2022-x64-ninja + variables: + CMAKE_CI_BUILD_NAME: windows_clang13.0_cl_ninja + CMAKE_CI_JOB_NIGHTLY: "true" + +t:windows-clang13.0-cl-nmake: + extends: + - .windows_clang_nmake + - .cmake_test_windows_clang + - .windows_tags_concurrent + - .cmake_junit_artifacts + - .run_dependent + dependencies: + - t:windows-vs2022-x64-ninja + needs: + - t:windows-vs2022-x64-ninja + variables: + CMAKE_CI_BUILD_NAME: windows_clang13.0_cl_nmake + CMAKE_CI_JOB_NIGHTLY: "true" + +t:windows-clang13.0-gnu-ninja: + extends: + - .windows_clang_ninja + - .cmake_test_windows_clang + - .windows_tags_concurrent + - .cmake_junit_artifacts + - .run_dependent + dependencies: + - t:windows-vs2022-x64-ninja + needs: + - t:windows-vs2022-x64-ninja + variables: + CMAKE_CI_BUILD_NAME: windows_clang13.0_gnu_ninja + CMAKE_CI_JOB_NIGHTLY: "true" + +t:windows-clang13.0-gnu-nmake: + extends: + - .windows_clang_nmake + - .cmake_test_windows_clang + - .windows_tags_concurrent + - .cmake_junit_artifacts + - .run_dependent + dependencies: + - t:windows-vs2022-x64-ninja + needs: + - t:windows-vs2022-x64-ninja + variables: + CMAKE_CI_BUILD_NAME: windows_clang13.0_gnu_nmake + CMAKE_CI_JOB_NIGHTLY: "true" + t:windows-msvc-v71-nmake: extends: - .windows_msvc_v71_nmake diff --git a/.gitlab/ci/clang.ps1 b/.gitlab/ci/clang.ps1 new file mode 100755 index 0000000..25d64ba --- /dev/null +++ b/.gitlab/ci/clang.ps1 @@ -0,0 +1,37 @@ +$erroractionpreference = "stop" + +if ("$env:CMAKE_CI_BUILD_NAME".Contains("clang13.0")) { + # LLVM/Clang 13.0 + # https://github.com/llvm/llvm-project/releases/tag/llvmorg-13.0.0 + $filename = "llvm-13.0.0-win-x86_64-1" + $sha256sum = "F1B7CE360DACBC9776D7F84BE714766D60CF3D47492AFE34C45D574D1C597264" +} else { + throw ('unknown CMAKE_CI_BUILD_NAME: ' + "$env:CMAKE_CI_BUILD_NAME") +} +$tarball = "$filename.zip" + +$outdir = $pwd.Path +$outdir = "$outdir\.gitlab" +$ProgressPreference = 'SilentlyContinue' +# This URL is only visible inside of Kitware's network. See above filename table. +Invoke-WebRequest -Uri "https://cmake.org/files/dependencies/internal/$tarball" -OutFile "$outdir\$tarball" +$hash = Get-FileHash "$outdir\$tarball" -Algorithm SHA256 +if ($hash.Hash -ne $sha256sum) { + exit 1 +} + +Add-Type -AssemblyName System.IO.Compression.FileSystem +[System.IO.Compression.ZipFile]::ExtractToDirectory("$outdir\$tarball", "$outdir") +Move-Item -Path "$outdir\$filename" -Destination "$outdir\llvm" + +$bin = "$outdir\llvm\bin" +$null = New-Item -ItemType HardLink -Path "$bin\clang++.exe" -Target "$bin\clang.exe" +$null = New-Item -ItemType HardLink -Path "$bin\clang-cl.exe" -Target "$bin\clang.exe" +$null = New-Item -ItemType HardLink -Path "$bin\clang-cpp.exe" -Target "$bin\clang.exe" +$null = New-Item -ItemType HardLink -Path "$bin\ld.lld.exe" -Target "$bin\lld.exe" +$null = New-Item -ItemType HardLink -Path "$bin\ld64.lld.exe" -Target "$bin\lld.exe" +$null = New-Item -ItemType HardLink -Path "$bin\lld-link.exe" -Target "$bin\lld.exe" +$null = New-Item -ItemType HardLink -Path "$bin\llvm-lib.exe" -Target "$bin\llvm-ar.exe" +$null = New-Item -ItemType HardLink -Path "$bin\llvm-ranlib.exe" -Target "$bin\llvm-ar.exe" +$null = New-Item -ItemType HardLink -Path "$bin\llvm-objcopy.exe" -Target "$bin\llvm-strip.exe" +Clear-Variable -Name bin diff --git a/.gitlab/ci/configure_windows_borland_common.cmake b/.gitlab/ci/configure_windows_borland_common.cmake index 6d66a05..55dce1d 100644 --- a/.gitlab/ci/configure_windows_borland_common.cmake +++ b/.gitlab/ci/configure_windows_borland_common.cmake @@ -1,2 +1,5 @@ +set(CMake_TEST_Java OFF CACHE BOOL "") + set(configure_no_sccache 1) + include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake") diff --git a/.gitlab/ci/configure_windows_clang_common.cmake b/.gitlab/ci/configure_windows_clang_common.cmake new file mode 100644 index 0000000..55dce1d --- /dev/null +++ b/.gitlab/ci/configure_windows_clang_common.cmake @@ -0,0 +1,5 @@ +set(CMake_TEST_Java OFF CACHE BOOL "") + +set(configure_no_sccache 1) + +include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake") diff --git a/.gitlab/ci/configure_windows_clang_ninja.cmake b/.gitlab/ci/configure_windows_clang_ninja.cmake new file mode 100644 index 0000000..ba19834 --- /dev/null +++ b/.gitlab/ci/configure_windows_clang_ninja.cmake @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_clang_common.cmake") diff --git a/.gitlab/ci/configure_windows_clang_nmake.cmake b/.gitlab/ci/configure_windows_clang_nmake.cmake new file mode 100644 index 0000000..ba19834 --- /dev/null +++ b/.gitlab/ci/configure_windows_clang_nmake.cmake @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_clang_common.cmake") diff --git a/.gitlab/ci/configure_windows_openwatcom_common.cmake b/.gitlab/ci/configure_windows_openwatcom_common.cmake index 6d66a05..55dce1d 100644 --- a/.gitlab/ci/configure_windows_openwatcom_common.cmake +++ b/.gitlab/ci/configure_windows_openwatcom_common.cmake @@ -1,2 +1,5 @@ +set(CMake_TEST_Java OFF CACHE BOOL "") + set(configure_no_sccache 1) + include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake") diff --git a/.gitlab/ci/env_windows_clang_common.cmake b/.gitlab/ci/env_windows_clang_common.cmake new file mode 100644 index 0000000..fdd668f --- /dev/null +++ b/.gitlab/ci/env_windows_clang_common.cmake @@ -0,0 +1,7 @@ +if("$ENV{CMAKE_CI_BUILD_NAME}" MATCHES "(^|_)gnu(_|$)") + set(ENV{CC} clang) + set(ENV{CXX} clang++) +else() + set(ENV{CC} clang-cl) + set(ENV{CXX} clang-cl) +endif() diff --git a/.gitlab/ci/env_windows_clang_ninja.cmake b/.gitlab/ci/env_windows_clang_ninja.cmake new file mode 100644 index 0000000..f3834a2 --- /dev/null +++ b/.gitlab/ci/env_windows_clang_ninja.cmake @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/env_windows_clang_common.cmake") diff --git a/.gitlab/ci/env_windows_clang_nmake.cmake b/.gitlab/ci/env_windows_clang_nmake.cmake new file mode 100644 index 0000000..f3834a2 --- /dev/null +++ b/.gitlab/ci/env_windows_clang_nmake.cmake @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/env_windows_clang_common.cmake") diff --git a/.gitlab/os-windows.yml b/.gitlab/os-windows.yml index 2bce8c8..d01c828 100644 --- a/.gitlab/os-windows.yml +++ b/.gitlab/os-windows.yml @@ -87,6 +87,14 @@ variables: CMAKE_CONFIGURATION: windows_borland5.8 +.windows_ninja: + extends: .windows + + variables: + CMAKE_GENERATOR: "Ninja" + CMAKE_CI_BUILD_TYPE: Release + CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true" + .windows_nmake: extends: .windows @@ -119,6 +127,22 @@ variables: CMAKE_CONFIGURATION: windows_vs2022_x64_jom +.windows_clang_ninja: + extends: + - .windows_ninja + - .windows_vcvarsall_vs2022_x64 + + variables: + CMAKE_CONFIGURATION: windows_clang_ninja + +.windows_clang_nmake: + extends: + - .windows_nmake + - .windows_vcvarsall_vs2022_x64 + + variables: + CMAKE_CONFIGURATION: windows_clang_nmake + .windows_msvc_v71_nmake: extends: .windows_nmake @@ -262,6 +286,20 @@ interruptible: true +.cmake_test_windows_clang: + stage: test-ext + + script: + - $pwdpath = $pwd.Path + - powershell -File ".gitlab/ci/ninja.ps1" + - Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab;$env:PATH" + - Invoke-Expression -Command .gitlab/ci/clang.ps1 + - Invoke-Expression -Command .gitlab/ci/vcvarsall.ps1 + - Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\llvm\bin;$env:PATH" + - build/install/bin/ctest --output-on-failure -V -S .gitlab/ci/ctest_test_external.cmake + + interruptible: true + .cmake_test_windows_msvc: stage: test-ext diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim index d5361bd..381d97c 100644 --- a/Auxiliary/vim/syntax/cmake.vim +++ b/Auxiliary/vim/syntax/cmake.vim @@ -381,6 +381,7 @@ syn keyword cmakeProperty contained \ VS_JUST_MY_CODE_DEBUGGING \ VS_KEYWORD \ VS_MOBILE_EXTENSIONS_VERSION + \ VS_NO_COMPILE_BATCHING \ VS_NO_SOLUTION_DEPLOY \ VS_PACKAGE_REFERENCES \ VS_PLATFORM_TOOLSET diff --git a/CMakeLists.txt b/CMakeLists.txt index b2ab30e..ffb93b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. -cmake_minimum_required(VERSION 3.1...3.21 FATAL_ERROR) +cmake_minimum_required(VERSION 3.1...3.22 FATAL_ERROR) set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideC.cmake) set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideCXX.cmake) diff --git a/Help/command/file.rst b/Help/command/file.rst index 799b6ff..2769577 100644 --- a/Help/command/file.rst +++ b/Help/command/file.rst @@ -1128,6 +1128,18 @@ Additional options to ``DOWNLOAD`` are: Historical short-hand for ``EXPECTED_HASH MD5=<value>``. It is an error to specify this if ``DOWNLOAD`` is not given a ``<file>``. +``RANGE_START <value>`` + .. versionadded:: 3.24 + + Offset of the start of the range in file in bytes. Could be omitted to + download up to the specified ``RANGE_END``. + +``RANGE_END <value>`` + .. versionadded:: 3.24 + + Offset of the end of the range in file in bytes. Could be omitted to + download everything from the specified ``RANGE_START`` to the end of file. + Locking ^^^^^^^ diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index df13dd0..0e9060d 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -1113,6 +1113,83 @@ Output-Related Expressions property, perhaps via the :command:`target_link_libraries` command, to specify private link dependencies without other usage requirements. +.. genex:: $<LINK_LIBRARY:feature,library-list> + + .. versionadded:: 3.24 + + Manage how libraries are specified during the link step. + This expression may be used to specify how to link libraries in a target. + For example: + + .. code-block:: cmake + + add_library(lib1 STATIC ...) + add_library(lib2 ...) + target_link_libraries(lib2 PRIVATE "$<LINK_LIBRARY:whole_archive,lib1>") + + This specify to use the ``lib1`` target with feature ``whole_archive`` for + linking target ``lib2``. The feature must have be defined by + :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>` variable or, if + :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` is false, + by :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>` variable. + + .. note:: + + The evaluation of this generator expression will use, for the following + variables, the values defined at the level of the creation of the target: + + * :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` + * :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>` + * :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` + * :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>` + + This expression can only be used to specify link libraries (i.e. part of + :command:`link_libraries` or :command:`target_link_libraries` commands and + :prop_tgt:`LINK_LIBRARIES` or :prop_tgt:`INTERFACE_LINK_LIBRARIES` target + properties). + + .. note:: + + If this expression appears in the :prop_tgt:`INTERFACE_LINK_LIBRARIES` + property of a target, it will be included in the imported target generated + by :command:`install(EXPORT)` command. It is the responsibility of the + environment consuming this import to define the link feature used by this + expression. + + The ``library-list`` argument can hold CMake targets or external libraries. + Any ``CMake`` target of type :ref:`OBJECT <Object Libraries>` or + :ref:`INTERFACE <Interface Libraries>` will be ignored by this expression and + will be handled in the standard way. + + Each target or external library involved in the link step must have only one + kind of feature (the absence of feature is also incompatible with any + feature). For example: + + .. code-block:: cmake + + add_library(lib1 ...) + + add_library(lib2 ...) + target_link_libraries(lib2 PUBLIC "$<LINK_LIBRARY:feature1,lib1>") + + add_library(lib3 ...) + target_link_libraries(lib3 PRIVATE lib1 lib2) + # an error will be raised here because lib1 has two different features + + To resolve such incompatibilities, the :prop_tgt:`LINK_LIBRARY_OVERRIDE` + and :prop_tgt:`LINK_LIBRARY_OVERRIDE_<LIBRARY>` target properties can be + used. + + .. note:: + + This expression does not guarantee that the list of specified libraries + will be kept grouped. So, constructs like ``start-group`` and + ``end-group``, as supported by ``GNU ld``, cannot be used. + + ``CMake`` pre-defines some features of general interest: + + .. include:: ../variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt + .. genex:: $<INSTALL_INTERFACE:...> Content of ``...`` when the property is exported using :command:`install(EXPORT)`, diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index f4efd3c..65f9248 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -308,6 +308,8 @@ Properties on Targets /prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG /prop_tgt/LINK_LIBRARIES /prop_tgt/LINK_LIBRARIES_ONLY_TARGETS + /prop_tgt/LINK_LIBRARY_OVERRIDE + /prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY /prop_tgt/LINK_OPTIONS /prop_tgt/LINK_SEARCH_END_STATIC /prop_tgt/LINK_SEARCH_START_STATIC @@ -402,6 +404,7 @@ Properties on Targets /prop_tgt/VS_JUST_MY_CODE_DEBUGGING /prop_tgt/VS_KEYWORD /prop_tgt/VS_MOBILE_EXTENSIONS_VERSION + /prop_tgt/VS_NO_COMPILE_BATCHING /prop_tgt/VS_NO_SOLUTION_DEPLOY /prop_tgt/VS_PACKAGE_REFERENCES /prop_tgt/VS_PLATFORM_TOOLSET diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 4df0237..b38f56c 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -437,6 +437,8 @@ Variables that Control the Build /variable/CMAKE_LANG_CPPCHECK /variable/CMAKE_LANG_CPPLINT /variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE + /variable/CMAKE_LANG_LINK_LIBRARY_USING_FEATURE + /variable/CMAKE_LANG_LINK_LIBRARY_USING_FEATURE_SUPPORTED /variable/CMAKE_LANG_LINKER_LAUNCHER /variable/CMAKE_LANG_LINK_LIBRARY_FILE_FLAG /variable/CMAKE_LANG_LINK_LIBRARY_FLAG @@ -450,6 +452,8 @@ Variables that Control the Build /variable/CMAKE_LINK_INTERFACE_LIBRARIES /variable/CMAKE_LINK_LIBRARY_FILE_FLAG /variable/CMAKE_LINK_LIBRARY_FLAG + /variable/CMAKE_LINK_LIBRARY_USING_FEATURE + /variable/CMAKE_LINK_LIBRARY_USING_FEATURE_SUPPORTED /variable/CMAKE_LINK_WHAT_YOU_USE /variable/CMAKE_LINK_WHAT_YOU_USE_CHECK /variable/CMAKE_MACOSX_BUNDLE diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index f7d4f6b..3c4e76a 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -299,7 +299,8 @@ Options "cmd": "add_executable", "args": ["foo", "bar"], "time": 1579512535.9687231, - "frame": 2 + "frame": 2, + "global_frame": 4 } The members are: @@ -309,7 +310,13 @@ Options was called. ``line`` - The line in ``file`` of the function call. + The line in ``file`` where the function call begins. + + ``line_end`` + If the function call spans multiple lines, this field will + be set to the line where the function call ends. If the function + calls spans a single line, this field will be unset. This field + was added in minor version 2 of the ``json-v1`` format. ``defer`` Optional member that is present when the function call was deferred @@ -326,7 +333,13 @@ Options Timestamp (seconds since epoch) of the function call. ``frame`` - Stack frame depth of the function that was called. + Stack frame depth of the function that was called, within the + context of the ``CMakeLists.txt`` being processed currently. + + ``global_frame`` + Stack frame depth of the function that was called, tracked globally + across all ``CMakeLists.txt`` files involved in the trace. This field + was added in minor version 2 of the ``json-v1`` format. Additionally, the first JSON document outputted contains the ``version`` key for the current major and minor version of the @@ -338,7 +351,7 @@ Options { "version": { "major": 1, - "minor": 1 + "minor": 2 } } @@ -646,11 +659,17 @@ Available commands are: ``true`` if cmake supports server-mode and ``false`` otherwise. Always false since CMake 3.20. -``cat <files>...`` +``cat [--] <files>...`` .. versionadded:: 3.18 Concatenate files and print on the standard output. + .. versionadded:: 3.24 + Added support for the double dash argument ``--``. This basic implementation + of ``cat`` does not support any options, so using a option starting with + ``-`` will result in an error. Use ``--`` to indicate the end of options, in + case a file starts with ``-``. + ``chdir <dir> <cmd> [<arg>...]`` Change the current working directory and run a command. @@ -719,11 +738,16 @@ Available commands are: ``echo_append [<string>...]`` Displays arguments as text but no new line. -``env [--unset=NAME]... [NAME=VALUE]... COMMAND [ARG]...`` +``env [--unset=NAME ...] [NAME=VALUE ...] [--] <command> [<arg>...]`` .. versionadded:: 3.1 Run command in a modified environment. + .. versionadded:: 3.24 + Added support for the double dash argument ``--``. Use ``--`` to stop + interpreting options/environment variables and treat the next argument as + the command, even if it start with ``-`` or contains a ``=``. + ``environment`` Display the current environment variables. @@ -816,16 +840,16 @@ Available commands are: Rename a file or directory (on one volume). If file with the ``<newname>`` name already exists, then it will be silently replaced. -``rm [-rRf] <file> <dir>...`` +``rm [-rRf] [--] <file|dir>...`` .. versionadded:: 3.17 Remove the files ``<file>`` or directories ``<dir>``. - Use ``-r`` or ``-R`` to remove directories and their contents recursively. If any of the listed files/directories do not exist, the command returns a non-zero exit code, but no message is logged. The ``-f`` option changes the behavior to return a zero exit code (i.e. success) in such - situations instead. + situations instead. Use ``--`` to stop interpreting options and treat all + remaining arguments as paths, even if they start with ``-``. ``server`` Launch :manual:`cmake-server(7)` mode. diff --git a/Help/prop_tgt/LINK_LIBRARY_OVERRIDE.rst b/Help/prop_tgt/LINK_LIBRARY_OVERRIDE.rst new file mode 100644 index 0000000..81a2a4a --- /dev/null +++ b/Help/prop_tgt/LINK_LIBRARY_OVERRIDE.rst @@ -0,0 +1,54 @@ +LINK_LIBRARY_OVERRIDE +--------------------- + +.. versionadded:: 3.24 + +To resolve incompatible features introduced by :genex:`LINK_LIBRARY` generator +expression, this property offers the possibility to override, per ``link-item`` +(``CMake`` target or external library) involved in the link step, any defined +features with a new one. + +This property takes a :ref:`;-list <CMake Language Lists>` of override +declarations which have the following format: + +:: + + feature[,link-item]* + +For the list of ``link-item`` (``CMake`` target or external library) specified, +the feature ``feature`` will be used in place of any declared feature. For +example: + +.. code-block:: cmake + + add_library(lib1 ...) + target_link_libraries(lib1 PUBLIC "$<LINK_LIBRARY:feature1,external>") + + add_library(lib2 ...) + target_link_libraries(lib2 PUBLIC "$<LINK_LIBRARY:feature2,lib1>") + + add_library(lib3 ...) + target_link_libraries(lib3 PRIVATE lib1 lib2) + # Here, lib1 has two different features which prevents to link lib3 + # So, define LINK_LIBRARY_OVERRIDE property to ensure correct link + set_property(TARGET lib3 PROPERTY LINK_LIBRARY_OVERRIDE "feature2,lib1,external") + # The lib1 and external will be used with FEATURE2 to link lib3 + +It is also possible to override any feature with the pre-defined feature +``DEFAULT`` to get the standard behavior (i.e. no feature): + +.. code-block:: cmake + + set_property(TARGET lib3 PROPERTY LINK_LIBRARY_OVERRIDE "DEFAULT,lib1" + "feature2,external") + # The lib1 will be used without any feature and external will use feature2 to link lib3 + +Contents of ``LINK_LIBRARY_OVERRIDE`` may use +:manual:`generator expressions <cmake-generator-expressions(7)>`. + +See also :prop_tgt:`LINK_LIBRARY_OVERRIDE_<LIBRARY>` target property for +a per linked target oriented approach to override features. + +For more information about features, see +:variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>` +and :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>` variables. diff --git a/Help/prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY.rst b/Help/prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY.rst new file mode 100644 index 0000000..112f614 --- /dev/null +++ b/Help/prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY.rst @@ -0,0 +1,45 @@ +LINK_LIBRARY_OVERRIDE_<LIBRARY> +------------------------------- + +.. versionadded:: 3.24 + +To resolve incompatible features introduced by :genex:`LINK_LIBRARY` generator +expression, this property offers the possibility to override, for a +``link-item`` (``CMake`` target or external library) involved in the link step, +any defined features with a new one. + +This property takes a ``feature`` name which will be applied to the +``link-item`` specified by ``<LIBRARY>`` suffix property. For example: + +.. code-block:: cmake + + add_library(lib1 ...) + target_link_libraries(lib1 PUBLIC "$<LINK_LIBRARY:feature1,external>") + + add_library(lib2 ...) + target_link_libraries(lib2 PUBLIC "$<LINK_LIBRARY:feature2,lib1>") + + add_library(lib3 ...) + target_link_libraries(lib3 PRIVATE lib1 lib2) + # Here, lib1 has two different features which prevents to link lib3 + # So, define LINK_LIBRARY_OVERRIDE_lib1 property to ensure correct link + set_property(TARGET lib3 PROPERTY LINK_LIBRARY_OVERRIDE_lib1 feature2) + # The lib1 will be used with feature2 to link lib3 + +It is also possible to override any feature with the pre-defined feature +``DEFAULT`` to get the standard behavior (i.e. no feature): + +.. code-block:: cmake + + set_property(TARGET lib3 PROPERTY LINK_LIBRARY_OVERRIDE_lib1 DEFAULT) + # The lib1 will be used without any feature to link lib3 + +Contents of ``LINK_LIBRARY_OVERRIDE_<LIBRARY>`` may use +:manual:`generator expressions <cmake-generator-expressions(7)>`. + +This property takes precedence over :prop_tgt:`LINK_LIBRARY_OVERRIDE` +target property. + +For more information about features, see +:variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>` +and :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>` variables. diff --git a/Help/prop_tgt/VS_NO_COMPILE_BATCHING.rst b/Help/prop_tgt/VS_NO_COMPILE_BATCHING.rst new file mode 100644 index 0000000..f8a9fa6 --- /dev/null +++ b/Help/prop_tgt/VS_NO_COMPILE_BATCHING.rst @@ -0,0 +1,21 @@ +VS_NO_COMPILE_BATCHING +---------------------- + +.. versionadded:: 3.24 + +Turn off compile batching for the target. Usually MSBuild calls the compiler +with multiple c/cpp files and compiler starts subprocesses for each file to +make the build parallel. If you want compiler to be invoked with one file at +a time set VS_NO_COMPILE_BATCHING to ON. If this flag is set MSBuild will call +compiler with one c/cpp file at a time. Useful when you want to use tool that +replaces the compiler, for example some build caching tool. + +Example +^^^^^^^ + +This shows setting the variable for the target foo. + +.. code-block:: cmake + + add_library(foo SHARED foo.cpp) + set_property(TARGET foo PROPERTY VS_NO_COMPILE_BATCHING ON) 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/Apple-link-framework.rst b/Help/release/dev/Apple-link-framework.rst new file mode 100644 index 0000000..e194c15 --- /dev/null +++ b/Help/release/dev/Apple-link-framework.rst @@ -0,0 +1,11 @@ +Apple-link-framework +-------------------- + +* The :genex:`LINK_LIBRARY` generator expression gained the ability to link + frameworks in various ways when targeting ``Apple`` platforms. The following + new features were added: + + * ``FRAMEWORK`` + * ``NEEDED_FRAMEWORK`` + * ``REEXPORT_FRAMEWORK`` + * ``WEAK_FRAMEWORK`` diff --git a/Help/release/dev/Genex-LINK_LIBRARY.rst b/Help/release/dev/Genex-LINK_LIBRARY.rst new file mode 100644 index 0000000..fe44dbc --- /dev/null +++ b/Help/release/dev/Genex-LINK_LIBRARY.rst @@ -0,0 +1,11 @@ +Genex-LINK_LIBRARY +------------------ + +* The :genex:`LINK_LIBRARY` generator expression was added to manage how + libraries are specified during the link step. The variables + :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>` and + :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>` are used to define features + usable by the :genex:`LINK_LIBRARY` generator expression. Moreover, the + :prop_tgt:`LINK_LIBRARY_OVERRIDE` and + :prop_tgt:`LINK_LIBRARY_OVERRIDE_<LIBRARY>` target properties are available + to resolve incompatible features. diff --git a/Help/release/dev/cmcmd-end-of-options-delimiter.rst b/Help/release/dev/cmcmd-end-of-options-delimiter.rst new file mode 100644 index 0000000..bc9cc21 --- /dev/null +++ b/Help/release/dev/cmcmd-end-of-options-delimiter.rst @@ -0,0 +1,7 @@ +cmcmd-end-of-options-delimiter +------------------------------ + +* The :manual:`cmake(1)` ``-E`` commands ``cat`` and ``env`` learned to respect + a double dash (``--``) argument that acts as a delimiter indicating the end of + options. Any following arguments are treated as operands/positional arguments, + even if they begin with a dash ``-`` character. diff --git a/Help/release/dev/file-download-range.rst b/Help/release/dev/file-download-range.rst new file mode 100644 index 0000000..194100d --- /dev/null +++ b/Help/release/dev/file-download-range.rst @@ -0,0 +1,6 @@ +file-download-range +------------------- + +* Add the fields ``RANGE_START`` and ``RANGE_END`` to ``file(DOWNLOAD)``. + Those fields provide a convenient way to specify the range, passed to the + libcurl, which can be useful for downloading parts of big binary files. diff --git a/Help/release/dev/trace-global-frame.rst b/Help/release/dev/trace-global-frame.rst new file mode 100644 index 0000000..fdc4b5c --- /dev/null +++ b/Help/release/dev/trace-global-frame.rst @@ -0,0 +1,8 @@ +trace-global-frame +------------------ + +* Add the field ``global_frame`` to the json-v1 trace format. This + frame tracks the depth of the call stack globally across all + ``CMakeLists.txt`` files involved in the trace, and will let tools + reconstruct stack traces that span from the top-level ``CMakeLists.txt`` + file of the project. diff --git a/Help/release/dev/trace-line-end.rst b/Help/release/dev/trace-line-end.rst new file mode 100644 index 0000000..beade4b --- /dev/null +++ b/Help/release/dev/trace-line-end.rst @@ -0,0 +1,7 @@ +trace-line-end +-------------- + +* Add the field ``line_end`` to the json-v1 trace format. This + field tells you the line in file ``file`` at which the function + call ends. Tools can use this new field, together with ``line`` + and ``file``, to map traces to lines of CMake source code. diff --git a/Help/release/dev/vs_buildcache_support.rst b/Help/release/dev/vs_buildcache_support.rst new file mode 100644 index 0000000..bdda675 --- /dev/null +++ b/Help/release/dev/vs_buildcache_support.rst @@ -0,0 +1,6 @@ +vs_buildcache_support +--------------------- + +* The :prop_tgt:`VS_NO_COMPILE_BATCHING` target property was added to + tell :ref:`Visual Studio Generators` whether to disable compiler parallelism + and call the compiler with one c/cpp file at a time. diff --git a/Help/release/index.rst b/Help/release/index.rst index ee677a3..ad33705 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_LANG_LINK_LIBRARY_USING_FEATURE.rst b/Help/variable/CMAKE_LANG_LINK_LIBRARY_USING_FEATURE.rst new file mode 100644 index 0000000..45b8aa8 --- /dev/null +++ b/Help/variable/CMAKE_LANG_LINK_LIBRARY_USING_FEATURE.rst @@ -0,0 +1,26 @@ +CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE> +----------------------------------------- + +.. versionadded:: 3.24 + +This variable defines, for the specified ``<FEATURE>`` and the linker language +``<LANG>``, the expression expected by the linker when libraries are specified +using :genex:`LINK_LIBRARY` generator expression. + +.. note:: + + Feature names defined in all uppercase are reserved to CMake. + +See also the associated variable +:variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` and +:variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>` variable for the definition of +features independent from the link language. + +.. include:: CMAKE_LINK_LIBRARY_USING_FEATURE.txt + +Predefined Features +^^^^^^^^^^^^^^^^^^^ + +``CMake`` pre-defines some features of general interest: + +.. include:: LINK_LIBRARY_PREDEFINED_FEATURES.txt diff --git a/Help/variable/CMAKE_LANG_LINK_LIBRARY_USING_FEATURE_SUPPORTED.rst b/Help/variable/CMAKE_LANG_LINK_LIBRARY_USING_FEATURE_SUPPORTED.rst new file mode 100644 index 0000000..e595bc7 --- /dev/null +++ b/Help/variable/CMAKE_LANG_LINK_LIBRARY_USING_FEATURE_SUPPORTED.rst @@ -0,0 +1,13 @@ +CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED +--------------------------------------------------- + +.. versionadded:: 3.24 + +Set to ``TRUE`` if the ``<FEATURE>``, as defined by variable +:variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>`, is supported for the +linker language ``<LANG>``. + +.. note:: + + This variable is evaluated before the more generic variable + :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED`. diff --git a/Help/variable/CMAKE_LINK_LIBRARY_USING_FEATURE.rst b/Help/variable/CMAKE_LINK_LIBRARY_USING_FEATURE.rst new file mode 100644 index 0000000..eae60c5 --- /dev/null +++ b/Help/variable/CMAKE_LINK_LIBRARY_USING_FEATURE.rst @@ -0,0 +1,31 @@ +CMAKE_LINK_LIBRARY_USING_<FEATURE> +---------------------------------- + +.. versionadded:: 3.24 + +This variable defines, for the specified ``FEATURE``, the expression expected +by the linker, regardless the linker language, when libraries are specified +using :genex:`LINK_LIBRARY` generator expression. + +.. note:: + + Feature names defined in all uppercase are reserved to CMake. + +See also the associated variable +:variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` and +:variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>` variable for the +definition of features dependent from the link language. + +This variable will be used by :genex:`LINK_LIBRARY` generator expression if, +for the linker language, the variable +:variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` is false or not +set. + +.. include:: CMAKE_LINK_LIBRARY_USING_FEATURE.txt + +Predefined Features +^^^^^^^^^^^^^^^^^^^ + +``CMake`` pre-defines some features of general interest: + +.. include:: LINK_LIBRARY_PREDEFINED_FEATURES.txt diff --git a/Help/variable/CMAKE_LINK_LIBRARY_USING_FEATURE.txt b/Help/variable/CMAKE_LINK_LIBRARY_USING_FEATURE.txt new file mode 100644 index 0000000..ad393b0 --- /dev/null +++ b/Help/variable/CMAKE_LINK_LIBRARY_USING_FEATURE.txt @@ -0,0 +1,112 @@ + +It can contain one or three elements. + +:: + + [<PREFIX>] <LIBRARY_EXPRESSION> [<SUFFIX>] + +When ``<PREFIX>`` and/or ``<SUFFIX>`` are specified, they encapsulate the list +of libraries. + +.. note:: + + Even if ``<PREFIX>`` and ``<SUFFIX>`` are specified, there is not guarantee + that the list of specified libraries, as part of :genex:`LINK_LIBRARY` + generator expression, will be kept grouped. So, constructs like + ``start-group`` and ``end-group``, as supported by ``GNU ld``, cannot be + used. + +``<LIBRARY_EXPRESSION>`` is used to specify the decoration for each +library. For that purpose, the patterns ``<LIBRARY>``, ``<LINK_ITEM>``, and +``<LIB_ITEM>`` are available: + +* ``<LIBRARY>`` is expanded to the library as computed by CMake. +* ``<LINK_ITEM>`` is expanded to the same expression as if the library was + specified in the standard way. +* ``<LIB_ITEM>`` is equivalent to ``<LIBRARY>`` for CMake targets and is + expanded to the item specified by the user for external libraries. + +Moreover, it is possible to have different decorations for paths (CMake targets +and external libraries specified with absolute paths) and other items specified +by name. For that purpose, ``PATH{}`` and ``NAME{}`` wrappers can be used. + +For all three elements of this variable, the ``LINKER:`` prefix can be used: + + .. include:: ../command/LINK_OPTIONS_LINKER.txt + :start-line: 3 + +Examples +^^^^^^^^ + +Loading a whole static library +"""""""""""""""""""""""""""""" + +A common need is the capability to load a whole static library. This capability +is offered by various environments but with a specific syntax: + +.. code-block:: cmake + + set(CMAKE_C_LINK_LIBRARY_USING_whole_archive_SUPPORTED TRUE) + if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + set(CMAKE_C_LINK_LIBRARY_USING_whole_archive "-force_load <LIB_ITEM>") + elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" + AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(CMAKE_C_LINK_LIBRARY_USING_whole_archive "LINKER:--push-state,--whole-archive" + "<LINK_ITEM>" + "LINKER:--pop-state") + elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_C_LINK_LIBRARY_USING_whole_archive "/WHOLEARCHIVE:<LIBRARY>") + else() + # feature not yet supported for the other environments + set(CMAKE_C_LINK_LIBRARY_USING_whole_archive_SUPPORTED FALSE) + endif() + + add_library(lib1 STATIC ...) + + add_library(lib2 SHARED ...) + if(CMAKE_C_LINK_LIBRARY_USING_whole_archive_SUPPORTED) + target_link_libraries(lib2 PRIVATE + "$<LINK_LIBRARY:whole_archive,lib1,$<IF:$<LINK_LANG_AND_ID:C,Clang>,libexternal.a,external>>") + else() + target_link_libraries(lib2 PRIVATE lib1 external) + endif() + +CMake will generate the following link expressions: + +* ``Clang``: ``-force_load /path/to/lib1.a -force_load libexternal.a`` +* ``GNU``: ``-Wl,--whole-archive /path/to/lib1.a -lexternal -Wl,--no-whole-archive`` +* ``MSVC``: ``/WHOLEARCHIVE:/path/to/lib1.lib /WHOLEARCHIVE:external.lib`` + +CMake will ensure, when possible, that ``<PREFIX>`` and ``<SUFFIX>`` are +not repeated for each library. + +In case of ``Clang``, the pattern ``<LIB_ITEM>`` is used because we need to +specify the library as defined by the user, not the name computed by CMake +(in that case ``external``). + +Linking a library as weak +""""""""""""""""""""""""" + +On MacOS, it is possible to link a library in weak mode (the library and all +references are marked as weak imports), but different flags must be used for a +library specified by path and by name. This constraint by be solved by using +``PATH{}`` and ``NAME{}`` wrappers: + +.. code-block:: cmake + + if (CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + set(CMAKE_LINK_LIBRARY_USING_weak_library + "PATH{-weak_library <LIBRARY>}NAME{LINKER:-weak-l<LIB_ITEM>}") + set(CMAKE_LINK_LIBRARY_USING_weak_library_SUPPORTED TRUE) + endif() + + add_library(lib SHARED ...) + add_executable(main ...) + if(CMAKE_LINK_LIBRARY_USING_weak_library_SUPPORTED) + target_link_libraries(main PRIVATE "$<LINK_LIBRARY:weak_library,lib,external>") + else() + target_link_libraries(main PRIVATE lib external) + endif() + +CMake will generate the following link expression: +``-weak_library /path/to/lib -Xlinker -weak-lexternal`` diff --git a/Help/variable/CMAKE_LINK_LIBRARY_USING_FEATURE_SUPPORTED.rst b/Help/variable/CMAKE_LINK_LIBRARY_USING_FEATURE_SUPPORTED.rst new file mode 100644 index 0000000..42b75fc --- /dev/null +++ b/Help/variable/CMAKE_LINK_LIBRARY_USING_FEATURE_SUPPORTED.rst @@ -0,0 +1,14 @@ +CMAKE_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED +-------------------------------------------- + +.. versionadded:: 3.24 + +Set to ``TRUE`` if the ``<FEATURE>``, as defined by variable +:variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>`, is supported regardless the +linker language. + +.. note:: + + This variable is evaluated if, and only if, the variable + :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` evaluates to + ``FALSE``. diff --git a/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt b/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt new file mode 100644 index 0000000..82c406a --- /dev/null +++ b/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt @@ -0,0 +1,47 @@ +**Features available in all environments** + +* ``DEFAULT``: This feature enables default link expression. This is mainly + useful with :prop_tgt:`LINK_LIBRARY_OVERRIDE` and + :prop_tgt:`LINK_LIBRARY_OVERRIDE_<LIBRARY>` target properties. + +**Features available in Apple environments** + +It is assumed that the linker used is the one provided by `XCode` or is +compatible with it. + +* ``FRAMEWORK``: This option tells the linker to search for the specified + framework (use linker option ``-framework``). +* ``NEEDED_FRAMEWORK``: This is the same as the ``FRAMEWORK`` feature but means + to really link with the framework even if no symbols are used from it (use + linker option ``-needed_framework``). +* ``REEXPORT_FRAMEWORK``: This is the same as the ``FRAMEWORK`` feature but + also specifies that all symbols in that framework should be available to + clients linking to the library being created (use linker option + ``-reexport_framework``). +* ``WEAK_FRAMEWORK``: This is the same as the ``FRAMEWORK`` feature but forces + the framework and all references to it to be marked as weak imports (use + linker option ``-weak_framework``). + +Features for framework linking have a special handling in ``CMake``: the +framework can be specified as a ``CMake`` framework target or file path. In the +first case, the target must have the :prop_tgt:`FRAMEWORK` target property set +as ``TRUE`` to enable framework handling. In the later case, if the path +includes a directory part, this one will be specified as framework search path +at link step. + +.. code-block:: cmake + + add_library(lib SHARED ...) + target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:NEEDED_FRAMEWORK,/path/to/my_framework>") + + # at link step we will have: + # -F/path/to -needed_framework my_framework + +.. note:: + + The expected formats for the file path, with optional parts specified as + ``()?``, are: + + * (/path/to/)?FwName(.framework)? + * (/path/to/)?FwName.framework/FwName + * (/path/to/)?FwName.framework/Versions/\*/FwName diff --git a/Modules/CMakeGenericSystem.cmake b/Modules/CMakeGenericSystem.cmake index 649b6f7..6e75fac 100644 --- a/Modules/CMakeGenericSystem.cmake +++ b/Modules/CMakeGenericSystem.cmake @@ -24,6 +24,12 @@ set(CMAKE_DL_LIBS "dl") set(CMAKE_FIND_LIBRARY_PREFIXES "lib") set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a") +# Define feature "DEFAULT" as supported. This special feature generates the +# default option to link a library +# This feature is intended to be used in LINK_LIBRARY_OVERRIDE and +# LINK_LIBRARY_OVERRIDE_<LIBRARY> target properties +set(CMAKE_LINK_LIBRARY_USING_DEFAULT_SUPPORTED TRUE) + set(CMAKE_AUTOGEN_ORIGIN_DEPENDS ON) set(CMAKE_AUTOMOC_COMPILER_PREDEFINES ON) if(NOT DEFINED CMAKE_AUTOMOC_PATH_PREFIX) diff --git a/Modules/Compiler/Clang-CUDA.cmake b/Modules/Compiler/Clang-CUDA.cmake index 219897e..e85ec67 100644 --- a/Modules/Compiler/Clang-CUDA.cmake +++ b/Modules/Compiler/Clang-CUDA.cmake @@ -38,3 +38,18 @@ set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_NONE "") if(UNIX) list(APPEND CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC "rt" "pthread" "dl") endif() + +if(APPLE) + # Defines host link features for frameworks + set(CMAKE_CUDA_LINK_LIBRARY_USING_FRAMEWORK "LINKER:-framework,<LIBRARY>") + set(CMAKE_CUDA_LINK_LIBRARY_USING_FRAMEWORK_SUPPORTED TRUE) + + set(CMAKE_CUDA_LINK_LIBRARY_USING_NEEDED_FRAMEWORK "LINKER:-needed_framework,<LIBRARY>") + set(CMAKE_CUDA_LINK_LIBRARY_USING_NEEDED_FRAMEWORK_SUPPORTED TRUE) + + set(CMAKE_CUDA_LINK_LIBRARY_USING_REEXPORT_FRAMEWORK "LINKER:-reexport_framework,<LIBRARY>") + set(CMAKE_CUDA_LINK_LIBRARY_USING_REEXPORT_FRAMEWORK_SUPPORTED TRUE) + + set(CMAKE_CUDA_LINK_LIBRARY_USING_WEAK_FRAMEWORK "LINKER:-weak_framework,<LIBRARY>") + set(CMAKE_CUDA_LINK_LIBRARY_USING_WEAK_FRAMEWORK_SUPPORTED TRUE) +endif() diff --git a/Modules/Internal/CPack/CPackRPM.cmake b/Modules/Internal/CPack/CPackRPM.cmake index c72bf6d..cd631b8 100644 --- a/Modules/Internal/CPack/CPackRPM.cmake +++ b/Modules/Internal/CPack/CPackRPM.cmake @@ -790,7 +790,7 @@ function(cpack_rpm_variable_fallback OUTPUT_VAR_NAME) set(FALLBACK_VAR_NAMES ${ARGN}) foreach(variable_name IN LISTS FALLBACK_VAR_NAMES) - if(${variable_name}) + if(DEFINED ${variable_name}) set(${OUTPUT_VAR_NAME} "${${variable_name}}" PARENT_SCOPE) break() endif() diff --git a/Modules/Platform/Apple-Apple-Swift.cmake b/Modules/Platform/Apple-Apple-Swift.cmake index 7ca3e36..9f604e8 100644 --- a/Modules/Platform/Apple-Apple-Swift.cmake +++ b/Modules/Platform/Apple-Apple-Swift.cmake @@ -1 +1,15 @@ set(CMAKE_Swift_SYSROOT_FLAG "-sdk") + + +# Defines host link features for frameworks +set(CMAKE_Swift_LINK_LIBRARY_USING_FRAMEWORK "LINKER:-framework,<LIBRARY>") +set(CMAKE_Swift_LINK_LIBRARY_USING_FRAMEWORK_SUPPORTED TRUE) + +set(CMAKE_Swift_LINK_LIBRARY_USING_NEEDED_FRAMEWORK "LINKER:-needed_framework,<LIBRARY>") +set(CMAKE_Swift_LINK_LIBRARY_USING_NEEDED_FRAMEWORK_SUPPORTED TRUE) + +set(CMAKE_Swift_LINK_LIBRARY_USING_REEXPORT_FRAMEWORK "LINKER:-reexport_framework,<LIBRARY>") +set(CMAKE_Swift_LINK_LIBRARY_USING_REEXPORT_FRAMEWORK_SUPPORTED TRUE) + +set(CMAKE_Swift_LINK_LIBRARY_USING_WEAK_FRAMEWORK "LINKER:-weak_framework,<LIBRARY>") +set(CMAKE_Swift_LINK_LIBRARY_USING_WEAK_FRAMEWORK_SUPPORTED TRUE) diff --git a/Modules/Platform/Apple-NVIDIA-CUDA.cmake b/Modules/Platform/Apple-NVIDIA-CUDA.cmake index 35e759a..0b8bbd9 100644 --- a/Modules/Platform/Apple-NVIDIA-CUDA.cmake +++ b/Modules/Platform/Apple-NVIDIA-CUDA.cmake @@ -17,3 +17,17 @@ set(CMAKE_SHARED_MODULE_CREATE_CUDA_FLAGS "-shared -Wl,-headerpad_max_install_na set(CMAKE_CUDA_CREATE_SHARED_LIBRARY "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> -o <TARGET> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> <OBJECTS> <LINK_LIBRARIES>${__IMPLICIT_LINKS}") set(CMAKE_CUDA_CREATE_SHARED_MODULE "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>${__IMPLICIT_LINKS}") + + +# Defines host link features for frameworks +set(CMAKE_CUDA_LINK_LIBRARY_USING_FRAMEWORK "LINKER:-framework,<LIBRARY>") +set(CMAKE_CUDA_LINK_LIBRARY_USING_FRAMEWORK_SUPPORTED TRUE) + +set(CMAKE_CUDA_LINK_LIBRARY_USING_NEEDED_FRAMEWORK "LINKER:-needed_framework,<LIBRARY>") +set(CMAKE_CUDA_LINK_LIBRARY_USING_NEEDED_FRAMEWORK_SUPPORTED TRUE) + +set(CMAKE_CUDA_LINK_LIBRARY_USING_REEXPORT_FRAMEWORK "LINKER:-reexport_framework,<LIBRARY>") +set(CMAKE_CUDA_LINK_LIBRARY_USING_REEXPORT_FRAMEWORK_SUPPORTED TRUE) + +set(CMAKE_CUDA_LINK_LIBRARY_USING_WEAK_FRAMEWORK "LINKER:-weak_framework,<LIBRARY>") +set(CMAKE_CUDA_LINK_LIBRARY_USING_WEAK_FRAMEWORK_SUPPORTED TRUE) diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake index 839dc81..74411e9 100644 --- a/Modules/Platform/Darwin.cmake +++ b/Modules/Platform/Darwin.cmake @@ -106,6 +106,19 @@ foreach(lang C CXX Fortran OBJC OBJCXX) # Set default framework search path flag for languages known to use a # preprocessor that may find headers in frameworks. set(CMAKE_${lang}_FRAMEWORK_SEARCH_FLAG -F) + + # Defines link features for frameworks + set(CMAKE_${lang}_LINK_LIBRARY_USING_FRAMEWORK "LINKER:-framework,<LIBRARY>") + set(CMAKE_${lang}_LINK_LIBRARY_USING_FRAMEWORK_SUPPORTED TRUE) + + set(CMAKE_${lang}_LINK_LIBRARY_USING_NEEDED_FRAMEWORK "LINKER:-needed_framework,<LIBRARY>") + set(CMAKE_${lang}_LINK_LIBRARY_USING_NEEDED_FRAMEWORK_SUPPORTED TRUE) + + set(CMAKE_${lang}_LINK_LIBRARY_USING_REEXPORT_FRAMEWORK "LINKER:-reexport_framework,<LIBRARY>") + set(CMAKE_${lang}_LINK_LIBRARY_USING_REEXPORT_FRAMEWORK_SUPPORTED TRUE) + + set(CMAKE_${lang}_LINK_LIBRARY_USING_WEAK_FRAMEWORK "LINKER:-weak_framework,<LIBRARY>") + set(CMAKE_${lang}_LINK_LIBRARY_USING_WEAK_FRAMEWORK_SUPPORTED TRUE) endforeach() # default to searching for frameworks first diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index ddcdd7e..d6e0096 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -358,6 +358,8 @@ set(SRCS cmLocalCommonGenerator.h cmLocalGenerator.cxx cmLocalGenerator.h + cmPlaceholderExpander.cxx + cmPlaceholderExpander.h cmRulePlaceholderExpander.cxx cmRulePlaceholderExpander.h cmLocalUnixMakefileGenerator3.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index b07c051..17149c3 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,8 +1,8 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 23) -set(CMake_VERSION_PATCH 0) -set(CMake_VERSION_RC 1) +set(CMake_VERSION_PATCH 20220218) +#set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) # Start with the full version number used in tags. It has no dev info. diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx index 789c78d..27d8cb8 100644 --- a/Source/cmCMakeLanguageCommand.cxx +++ b/Source/cmCMakeLanguageCommand.cxx @@ -84,7 +84,8 @@ bool cmCMakeLanguageCommandCALL(std::vector<cmListFileArgument> const& args, for (size_t i = startArg; i < args.size(); ++i) { funcArgs.emplace_back(args[i].Value, args[i].Delim, context.Line); } - cmListFileFunction func{ callCommand, context.Line, std::move(funcArgs) }; + cmListFileFunction func{ callCommand, context.Line, context.Line, + std::move(funcArgs) }; if (defer) { if (defer->Id.empty()) { diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx index 1b11f20..abec968 100644 --- a/Source/cmCPluginAPI.cxx +++ b/Source/cmCPluginAPI.cxx @@ -432,7 +432,7 @@ static int CCONV cmExecuteCommand(void* arg, const char* name, int numArgs, lffArgs.emplace_back(args[i], cmListFileArgument::Quoted, 0); } - cmListFileFunction lff{ name, 0, std::move(lffArgs) }; + cmListFileFunction lff{ name, 0, 0, std::move(lffArgs) }; cmExecutionStatus status(*mf); return mf->ExecuteCommand(lff, status); } diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 370ddff..d22a4f2 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -11,13 +11,18 @@ #include <utility> #include <cm/memory> +#include <cm/string_view> +#include <cmext/string_view> #include "cmComputeComponentGraph.h" +#include "cmGeneratorExpression.h" +#include "cmGeneratorExpressionDAGChecker.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmRange.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -174,8 +179,36 @@ items that we know the linker will re-use automatically (shared libs). */ +namespace { +const auto LL_BEGIN = "<LINK_LIBRARY:"_s; +const auto LL_END = "</LINK_LIBRARY:"_s; + +inline std::string ExtractFeature(std::string const& item) +{ + return item.substr(LL_BEGIN.length(), + item.find('>', LL_BEGIN.length()) - LL_BEGIN.length()); +} + +bool IsFeatureSupported(cmMakefile* makefile, std::string const& linkLanguage, + std::string const& feature) +{ + auto featureSupported = cmStrCat( + "CMAKE_", linkLanguage, "_LINK_LIBRARY_USING_", feature, "_SUPPORTED"); + if (makefile->GetDefinition(featureSupported).IsOn()) { + return true; + } + + featureSupported = + cmStrCat("CMAKE_LINK_LIBRARY_USING_", feature, "_SUPPORTED"); + return makefile->GetDefinition(featureSupported).IsOn(); +} +} + +const std::string cmComputeLinkDepends::LinkEntry::DEFAULT = "DEFAULT"; + cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, - const std::string& config) + const std::string& config, + const std::string& linkLanguage) { // Store context information. this->Target = target; @@ -183,6 +216,50 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, this->GlobalGenerator = this->Target->GetLocalGenerator()->GetGlobalGenerator(); this->CMakeInstance = this->GlobalGenerator->GetCMakeInstance(); + this->LinkLanguage = linkLanguage; + + // target oriented feature override property takes precedence over + // global override property + cm::string_view lloPrefix = "LINK_LIBRARY_OVERRIDE_"_s; + auto const& keys = this->Target->GetPropertyKeys(); + std::for_each( + keys.cbegin(), keys.cend(), + [this, &lloPrefix, &config, &linkLanguage](std::string const& key) { + if (cmHasPrefix(key, lloPrefix)) { + if (cmValue feature = this->Target->GetProperty(key)) { + if (!feature->empty() && key.length() > lloPrefix.length()) { + auto item = key.substr(lloPrefix.length()); + cmGeneratorExpressionDAGChecker dag{ this->Target->GetBacktrace(), + this->Target, + "LINK_LIBRARY_OVERRIDE", + nullptr, nullptr }; + auto overrideFeature = cmGeneratorExpression::Evaluate( + feature, this->Target->GetLocalGenerator(), config, this->Target, + &dag, this->Target, linkLanguage); + this->LinkLibraryOverride.emplace(item, overrideFeature); + } + } + } + }); + // global override property + if (cmValue linkLibraryOverride = + this->Target->GetProperty("LINK_LIBRARY_OVERRIDE")) { + cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target, + "LINK_LIBRARY_OVERRIDE", nullptr, + nullptr }; + auto overrideValue = cmGeneratorExpression::Evaluate( + linkLibraryOverride, target->GetLocalGenerator(), config, target, &dag, + target, linkLanguage); + + auto overrideList = cmTokenize(overrideValue, ","_s); + if (overrideList.size() >= 2) { + auto const& feature = overrideList.front(); + for_each(overrideList.cbegin() + 1, overrideList.cend(), + [this, &feature](std::string const& item) { + this->LinkLibraryOverride.emplace(item, feature); + }); + } + } // The configuration being linked. this->HasConfig = !config.empty(); @@ -249,7 +326,7 @@ cmComputeLinkDepends::Compute() } // Compute the final ordering. - this->OrderLinkEntires(); + this->OrderLinkEntries(); // Compute the final set of link entries. // Iterate in reverse order so we can keep only the last occurrence @@ -281,32 +358,40 @@ cmComputeLinkDepends::Compute() return this->FinalLinkEntries; } -std::map<cmLinkItem, int>::iterator cmComputeLinkDepends::AllocateLinkEntry( - cmLinkItem const& item) +std::string const& cmComputeLinkDepends::GetCurrentFeature( + std::string const& item, std::string const& defaultFeature) const +{ + auto it = this->LinkLibraryOverride.find(item); + return it == this->LinkLibraryOverride.end() ? defaultFeature : it->second; +} + +std::pair<std::map<cmLinkItem, int>::iterator, bool> +cmComputeLinkDepends::AllocateLinkEntry(cmLinkItem const& item) { std::map<cmLinkItem, int>::value_type index_entry( item, static_cast<int>(this->EntryList.size())); - auto lei = this->LinkEntryIndex.insert(index_entry).first; - this->EntryList.emplace_back(); - this->InferredDependSets.emplace_back(); - this->EntryConstraintGraph.emplace_back(); + auto lei = this->LinkEntryIndex.insert(index_entry); + if (lei.second) { + this->EntryList.emplace_back(); + this->InferredDependSets.emplace_back(); + this->EntryConstraintGraph.emplace_back(); + } return lei; } -int cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item) +std::pair<int, bool> cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item) { + // Allocate a spot for the item entry. + auto lei = this->AllocateLinkEntry(item); + // Check if the item entry has already been added. - auto lei = this->LinkEntryIndex.find(item); - if (lei != this->LinkEntryIndex.end()) { + if (!lei.second) { // Yes. We do not need to follow the item's dependencies again. - return lei->second; + return { lei.first->second, false }; } - // Allocate a spot for the item entry. - lei = this->AllocateLinkEntry(item); - // Initialize the item entry. - int index = lei->second; + int index = lei.first->second; LinkEntry& entry = this->EntryList[index]; entry.Item = BT<std::string>(item.AsStr(), item.Backtrace); entry.Target = item.Target; @@ -332,22 +417,21 @@ int cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item) } } - return index; + return { index, true }; } void cmComputeLinkDepends::AddLinkObject(cmLinkItem const& item) { + // Allocate a spot for the item entry. + auto lei = this->AllocateLinkEntry(item); + // Check if the item entry has already been added. - auto lei = this->LinkEntryIndex.find(item); - if (lei != this->LinkEntryIndex.end()) { + if (!lei.second) { return; } - // Allocate a spot for the item entry. - lei = this->AllocateLinkEntry(item); - // Initialize the item entry. - int index = lei->second; + int index = lei.first->second; LinkEntry& entry = this->EntryList[index]; entry.Item = BT<std::string>(item.AsStr(), item.Backtrace); entry.IsObject = true; @@ -423,14 +507,14 @@ void cmComputeLinkDepends::QueueSharedDependencies( void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep) { - // Check if the target already has an entry. - auto lei = this->LinkEntryIndex.find(dep.Item); - if (lei == this->LinkEntryIndex.end()) { - // Allocate a spot for the item entry. - lei = this->AllocateLinkEntry(dep.Item); + // Allocate a spot for the item entry. + auto lei = this->AllocateLinkEntry(dep.Item); + int index = lei.first->second; + // Check if the target does not already has an entry. + if (lei.second) { // Initialize the item entry. - LinkEntry& entry = this->EntryList[lei->second]; + LinkEntry& entry = this->EntryList[index]; entry.Item = BT<std::string>(dep.Item.AsStr(), dep.Item.Backtrace); entry.Target = dep.Item.Target; @@ -441,7 +525,6 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep) } // Get the link entry for this target. - int index = lei->second; LinkEntry& entry = this->EntryList[index]; // This shared library dependency must follow the item that listed @@ -541,6 +624,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index, { // Track inferred dependency sets implied by this list. std::map<int, DependSet> dependSets; + std::string feature = LinkEntry::DEFAULT; // Loop over the libraries linked directly by the depender. for (T const& l : libs) { @@ -550,9 +634,89 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index, if (item.AsStr() == this->Target->GetName() || item.AsStr().empty()) { continue; } + if (cmHasPrefix(item.AsStr(), LL_BEGIN) && + cmHasSuffix(item.AsStr(), '>')) { + feature = ExtractFeature(item.AsStr()); + // emit a warning if an undefined feature is used as part of + // an imported target + if (depender_index >= 0) { + const auto& depender = this->EntryList[depender_index]; + if (depender.Target != nullptr && depender.Target->IsImported() && + !IsFeatureSupported(this->Makefile, this->LinkLanguage, feature)) { + this->CMakeInstance->IssueMessage( + MessageType::AUTHOR_ERROR, + cmStrCat("The 'IMPORTED' target '", depender.Target->GetName(), + "' uses the generator-expression '$<LINK_LIBRARY>' with " + "the feature '", + feature, + "', which is undefined or unsupported.\nDid you miss to " + "define it by setting variables \"CMAKE_", + this->LinkLanguage, "_LINK_LIBRARY_USING_", feature, + "\" and \"CMAKE_", this->LinkLanguage, + "_LINK_LIBRARY_USING_", feature, "_SUPPORTED\"?"), + this->Target->GetBacktrace()); + } + } + continue; + } + if (cmHasPrefix(item.AsStr(), LL_END) && cmHasSuffix(item.AsStr(), '>')) { + feature = LinkEntry::DEFAULT; + continue; + } // Add a link entry for this item. - int dependee_index = this->AddLinkEntry(l); + auto ale = this->AddLinkEntry(item); + int dependee_index = ale.first; + LinkEntry& entry = this->EntryList[dependee_index]; + auto const& itemFeature = + this->GetCurrentFeature(entry.Item.Value, feature); + if (itemFeature != LinkEntry::DEFAULT) { + if (ale.second) { + // current item not yet defined + if (entry.Target != nullptr && + (entry.Target->GetType() == + cmStateEnums::TargetType::OBJECT_LIBRARY || + entry.Target->GetType() == + cmStateEnums::TargetType::INTERFACE_LIBRARY)) { + this->CMakeInstance->IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat("The feature '", feature, + "', specified as part of a generator-expression " + "'$", + LL_BEGIN, feature, ">', will not be applied to the ", + (entry.Target->GetType() == + cmStateEnums::TargetType::OBJECT_LIBRARY + ? "OBJECT" + : "INTERFACE"), + " library '", entry.Item.Value, "'."), + this->Target->GetBacktrace()); + } else { + entry.Feature = itemFeature; + } + } + } + + bool supportedItem = entry.Target == nullptr || + (entry.Target->GetType() != cmStateEnums::TargetType::OBJECT_LIBRARY && + entry.Target->GetType() != cmStateEnums::TargetType::INTERFACE_LIBRARY); + + if (supportedItem && entry.Feature != itemFeature) { + // incompatibles features occurred + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Impossible to link target '", this->Target->GetName(), + "' because the link item '", entry.Item.Value, + "', specified ", + (itemFeature == LinkEntry::DEFAULT + ? "without any feature or 'DEFAULT' feature" + : cmStrCat("with the feature '", itemFeature, '\'')), + ", has already occurred ", + (entry.Feature == LinkEntry::DEFAULT + ? "without any feature or 'DEFAULT' feature" + : cmStrCat("with the feature '", entry.Feature, '\'')), + ", which is not allowed."), + this->Target->GetBacktrace()); + } // The dependee must come after the depender. if (depender_index >= 0) { @@ -667,7 +831,7 @@ void cmComputeLinkDepends::DisplayConstraintGraph() fprintf(stderr, "%s\n", e.str().c_str()); } -void cmComputeLinkDepends::OrderLinkEntires() +void cmComputeLinkDepends::OrderLinkEntries() { // Compute the DAG of strongly connected components. The algorithm // used by cmComputeComponentGraph should identify the components in @@ -869,10 +1033,14 @@ void cmComputeLinkDepends::DisplayFinalEntries() fprintf(stderr, "target [%s] links to:\n", this->Target->GetName().c_str()); for (LinkEntry const& lei : this->FinalLinkEntries) { if (lei.Target) { - fprintf(stderr, " target [%s]\n", lei.Target->GetName().c_str()); + fprintf(stderr, " target [%s]", lei.Target->GetName().c_str()); } else { - fprintf(stderr, " item [%s]\n", lei.Item.Value.c_str()); + fprintf(stderr, " item [%s]", lei.Item.Value.c_str()); + } + if (lei.Feature != LinkEntry::DEFAULT) { + fprintf(stderr, ", feature [%s]", lei.Feature.c_str()); } + fprintf(stderr, "\n"); } fprintf(stderr, "\n"); } diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 72316f1..64603e0 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -9,6 +9,7 @@ #include <queue> #include <set> #include <string> +#include <utility> #include <vector> #include "cmGraphAdjacencyList.h" @@ -29,7 +30,8 @@ class cmComputeLinkDepends { public: cmComputeLinkDepends(cmGeneratorTarget const* target, - const std::string& config); + const std::string& config, + const std::string& linkLanguage); ~cmComputeLinkDepends(); cmComputeLinkDepends(const cmComputeLinkDepends&) = delete; @@ -38,11 +40,23 @@ public: // Basic information about each link item. struct LinkEntry { + LinkEntry() = default; + LinkEntry(BT<std::string> item, cmGeneratorTarget const* target = nullptr) + : Item(std::move(item)) + , Target(target) + { + } + + static const std::string DEFAULT; + BT<std::string> Item; cmGeneratorTarget const* Target = nullptr; bool IsSharedDep = false; bool IsFlag = false; bool IsObject = false; + // The following member is for the management of items specified + // through genex $<LINK_LIBRARY:...> + std::string Feature = std::string(DEFAULT); }; using EntryVector = std::vector<LinkEntry>; @@ -60,12 +74,17 @@ private: cmMakefile* Makefile; cmGlobalGenerator const* GlobalGenerator; cmake* CMakeInstance; + std::string LinkLanguage; std::string Config; EntryVector FinalLinkEntries; + std::map<std::string, std::string> LinkLibraryOverride; + + std::string const& GetCurrentFeature( + std::string const& item, std::string const& defaultFeature) const; - std::map<cmLinkItem, int>::iterator AllocateLinkEntry( + std::pair<std::map<cmLinkItem, int>::iterator, bool> AllocateLinkEntry( cmLinkItem const& item); - int AddLinkEntry(cmLinkItem const& item); + std::pair<int, bool> AddLinkEntry(cmLinkItem const& item); void AddLinkObject(cmLinkItem const& item); void AddVarLinkEntries(int depender_index, const char* value); void AddDirectLinkEntries(); @@ -123,7 +142,7 @@ private: void DisplayConstraintGraph(); // Ordering algorithm. - void OrderLinkEntires(); + void OrderLinkEntries(); std::vector<char> ComponentVisited; std::vector<int> ComponentOrder; diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 2ff91fe..9df2044 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -8,7 +8,9 @@ #include <utility> #include <cm/memory> +#include <cm/optional> #include <cmext/algorithm> +#include <cmext/string_view> #include "cmComputeLinkDepends.h" #include "cmGeneratorTarget.h" @@ -18,7 +20,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmOrderDirectories.h" -#include "cmOutputConverter.h" +#include "cmPlaceholderExpander.h" #include "cmPolicies.h" #include "cmState.h" #include "cmStateTypes.h" @@ -344,6 +346,27 @@ cmComputeLinkInformation::cmComputeLinkInformation( this->LinkWithRuntimePath = this->Makefile->IsOn(var); } + // Define some Feature descriptors to handle standard library and object link + if (!this->GetLibLinkFileFlag().empty()) { + this->LibraryFeatureDescriptors.emplace( + "__CMAKE_LINK_LIBRARY", + FeatureDescriptor{ "__CMAKE_LINK_LIBRARY", + cmStrCat(this->GetLibLinkFileFlag(), "<LIBRARY>") }); + } + if (!this->GetObjLinkFileFlag().empty()) { + this->LibraryFeatureDescriptors.emplace( + "__CMAKE_LINK_OBJECT", + FeatureDescriptor{ "__CMAKE_LINK_OBJECT", + cmStrCat(this->GetObjLinkFileFlag(), "<LIBRARY>") }); + } + if (!this->LoaderFlag->empty()) { + // Define a Feature descriptor for the link of an executable with exports + this->LibraryFeatureDescriptors.emplace( + "__CMAKE_LINK_EXECUTABLE", + FeatureDescriptor{ "__CMAKE_LINK_EXECUTABLE", + cmStrCat(this->LoaderFlag, "<LIBRARY>") }); + } + // Check the platform policy for missing soname case. this->NoSONameUsesPath = this->Makefile->IsOn("CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME"); @@ -409,6 +432,10 @@ cmComputeLinkInformation::cmComputeLinkInformation( cmComputeLinkInformation::~cmComputeLinkInformation() = default; +namespace { +const std::string& DEFAULT = cmComputeLinkDepends::LinkEntry::DEFAULT; +} + void cmComputeLinkInformation::AppendValues( std::string& result, std::vector<BT<std::string>>& values) { @@ -510,17 +537,54 @@ bool cmComputeLinkInformation::Compute() } // Compute the ordered link line items. - cmComputeLinkDepends cld(this->Target, this->Config); + cmComputeLinkDepends cld(this->Target, this->Config, this->LinkLanguage); cld.SetOldLinkDirMode(this->OldLinkDirMode); cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute(); + FeatureDescriptor const* currentFeature = nullptr; // Add the link line items. for (cmComputeLinkDepends::LinkEntry const& linkEntry : linkEntries) { + if (currentFeature != nullptr && + linkEntry.Feature != currentFeature->Name) { + // emit feature suffix, if any + if (!currentFeature->Suffix.empty()) { + this->Items.emplace_back( + BT<std::string>{ currentFeature->Suffix, + this->Items.back().Value.Backtrace }, + ItemIsPath::No); + } + currentFeature = nullptr; + } + + if (linkEntry.Feature != DEFAULT && + (currentFeature == nullptr || + linkEntry.Feature != currentFeature->Name)) { + if (!this->AddLibraryFeature(linkEntry.Feature)) { + continue; + } + currentFeature = this->FindLibraryFeature(linkEntry.Feature); + // emit feature prefix, if any + if (!currentFeature->Prefix.empty()) { + this->Items.emplace_back( + BT<std::string>{ currentFeature->Prefix, linkEntry.Item.Backtrace }, + ItemIsPath::No); + } + } + if (linkEntry.IsSharedDep) { - this->AddSharedDepItem(linkEntry.Item, linkEntry.Target); + this->AddSharedDepItem(linkEntry); } else { - this->AddItem(linkEntry.Item, linkEntry.Target, - linkEntry.IsObject ? ItemIsObject::Yes : ItemIsObject::No); + this->AddItem(linkEntry); + } + } + + if (currentFeature != nullptr) { + // emit feature suffix, if any + if (!currentFeature->Suffix.empty()) { + this->Items.emplace_back( + BT<std::string>{ currentFeature->Suffix, + this->Items.back().Value.Backtrace }, + ItemIsPath::No); } } @@ -576,6 +640,270 @@ bool cmComputeLinkInformation::Compute() return true; } +namespace { +void FinalizeFeatureFormat(std::string& format, const std::string& activeTag, + const std::string& otherTag) +{ + auto pos = format.find(otherTag); + if (pos != std::string::npos) { + format.erase(pos, format.find('}', pos) - pos + 1); + } + pos = format.find(activeTag); + if (pos != std::string::npos) { + format.erase(pos, activeTag.length()); + pos = format.find('}', pos); + if (pos != std::string::npos) { + format.erase(pos, 1); + } + } +} + +bool IsValidFeatureFormat(const std::string& format) +{ + return format.find("<LIBRARY>") != std::string::npos || + format.find("<LIB_ITEM>") != std::string::npos || + format.find("<LINK_ITEM>") != std::string::npos; +} +} + +bool cmComputeLinkInformation::AddLibraryFeature(std::string const& feature) +{ + auto it = this->LibraryFeatureDescriptors.find(feature); + if (it != this->LibraryFeatureDescriptors.end()) { + return it->second.Supported; + } + + auto featureName = + cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_LIBRARY_USING_", feature); + cmValue featureSupported = + this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED")); + if (!featureSupported.IsOn()) { + featureName = cmStrCat("CMAKE_LINK_LIBRARY_USING_", feature); + featureSupported = + this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED")); + } + if (!featureSupported.IsOn()) { + this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{}); + + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat( + "Feature '", feature, + "', specified through generator-expression '$<LINK_LIBRARY>' to " + "link target '", + this->Target->GetName(), "', is not supported for the '", + this->LinkLanguage, "' link language."), + this->Target->GetBacktrace()); + + return false; + } + + cmValue langFeature = this->Makefile->GetDefinition(featureName); + if (!langFeature) { + this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{}); + + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat( + "Feature '", feature, + "', specified through generator-expression '$<LINK_LIBRARY>' to " + "link target '", + this->Target->GetName(), "', is not defined for the '", + this->LinkLanguage, "' link language."), + this->Target->GetBacktrace()); + + return false; + } + + auto items = + cmExpandListWithBacktrace(langFeature, this->Target->GetBacktrace(), true); + + if ((items.size() == 1 && !IsValidFeatureFormat(items.front().Value)) || + (items.size() == 3 && !IsValidFeatureFormat(items[1].Value))) { + this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{}); + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Feature '", feature, "', specified by variable '", featureName, + "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or " + "\"<LINK_ITEM>\" patterns " + "are missing) and cannot be used to link target '", + this->Target->GetName(), "'."), + this->Target->GetBacktrace()); + + return false; + } + + // now, handle possible "PATH{}" and "NAME{}" patterns + if (items.size() == 1) { + items.push_back(items.front()); + FinalizeFeatureFormat(items[0].Value, "PATH{", "NAME{"); + FinalizeFeatureFormat(items[1].Value, "NAME{", "PATH{"); + } else if (items.size() == 3) { + items.insert(items.begin() + 1, items[1]); + FinalizeFeatureFormat(items[1].Value, "PATH{", "NAME{"); + FinalizeFeatureFormat(items[2].Value, "NAME{", "PATH{"); + } else { + this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{}); + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Feature '", feature, "', specified by variable '", featureName, + "', is malformed (wrong number of elements) and cannot be used " + "to link target '", + this->Target->GetName(), "'."), + this->Target->GetBacktrace()); + + return false; + } + if ((items.size() == 2 && !IsValidFeatureFormat(items[0].Value)) || + (items.size() == 4 && !IsValidFeatureFormat(items[1].Value))) { + // PATH{} has wrong format + this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{}); + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Feature '", feature, "', specified by variable '", featureName, + "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or " + "\"<LINK_ITEM>\" patterns " + "are missing for \"PATH{}\" alternative) and cannot be used to " + "link target '", + this->Target->GetName(), "'."), + this->Target->GetBacktrace()); + + return false; + } + if ((items.size() == 2 && !IsValidFeatureFormat(items[1].Value)) || + (items.size() == 4 && !IsValidFeatureFormat(items[2].Value))) { + // NAME{} has wrong format + this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{}); + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Feature '", feature, "', specified by variable '", featureName, + "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or " + "\"<LINK_ITEM>\" patterns " + "are missing for \"NAME{}\" alternative) and cannot be used to " + "link target '", + this->Target->GetName(), "'."), + this->Target->GetBacktrace()); + + return false; + } + + // replace LINKER: pattern + this->Target->ResolveLinkerWrapper(items, this->LinkLanguage, true); + + if (items.size() == 2) { + this->LibraryFeatureDescriptors.emplace( + feature, FeatureDescriptor{ feature, items[0].Value, items[1].Value }); + } else { + this->LibraryFeatureDescriptors.emplace( + feature, + FeatureDescriptor{ feature, items[0].Value, items[1].Value, + items[2].Value, items[3].Value }); + } + + return true; +} + +cmComputeLinkInformation::FeatureDescriptor const& +cmComputeLinkInformation::GetLibraryFeature(std::string const& feature) const +{ + return this->LibraryFeatureDescriptors.find(feature)->second; +} +cmComputeLinkInformation::FeatureDescriptor const* +cmComputeLinkInformation::FindLibraryFeature(std::string const& feature) const +{ + auto it = this->LibraryFeatureDescriptors.find(feature); + if (it == this->LibraryFeatureDescriptors.end()) { + return nullptr; + } + + return &it->second; +} + +namespace { +class FeaturePlaceHolderExpander : public cmPlaceholderExpander +{ +public: + FeaturePlaceHolderExpander(const std::string* library, + const std::string* libItem = nullptr, + const std::string* linkItem = nullptr) + : Library(library) + , LibItem(libItem) + , LinkItem(linkItem) + { + } + +private: + std::string ExpandVariable(std::string const& variable) override + { + if (this->Library != nullptr && variable == "LIBRARY") { + return *this->Library; + } + if (this->LibItem != nullptr && variable == "LIB_ITEM") { + return *this->LibItem; + } + if (this->LinkItem != nullptr && variable == "LINK_ITEM") { + return *this->LinkItem; + } + + return variable; + } + + const std::string* Library = nullptr; + const std::string* LibItem = nullptr; + const std::string* LinkItem = nullptr; +}; +} + +cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor( + std::string name, std::string itemFormat) + : Name(std::move(name)) + , Supported(true) + , ItemPathFormat(std::move(itemFormat)) + , ItemNameFormat(this->ItemPathFormat) +{ +} +cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor( + std::string name, std::string itemPathFormat, std::string itemNameFormat) + : Name(std::move(name)) + , Supported(true) + , ItemPathFormat(std::move(itemPathFormat)) + , ItemNameFormat(std::move(itemNameFormat)) +{ +} +cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor( + std::string name, std::string prefix, std::string itemPathFormat, + std::string itemNameFormat, std::string suffix) + : Name(std::move(name)) + , Supported(true) + , Prefix(std::move(prefix)) + , Suffix(std::move(suffix)) + , ItemPathFormat(std::move(itemPathFormat)) + , ItemNameFormat(std::move(itemNameFormat)) +{ +} + +std::string cmComputeLinkInformation::FeatureDescriptor::GetDecoratedItem( + std::string const& library, ItemIsPath isPath) const +{ + auto format = + isPath == ItemIsPath::Yes ? this->ItemPathFormat : this->ItemNameFormat; + + // replace <LIBRARY>, <LIB_ITEM> and <LINK_ITEM> patterns with library path + FeaturePlaceHolderExpander expander(&library, &library, &library); + return expander.ExpandVariables(format); +} +std::string cmComputeLinkInformation::FeatureDescriptor::GetDecoratedItem( + std::string const& library, std::string const& libItem, + std::string const& linkItem, ItemIsPath isPath) const +{ + auto format = + isPath == ItemIsPath::Yes ? this->ItemPathFormat : this->ItemNameFormat; + + // replace <LIBRARY>, <LIB_ITEM> and <LINK_ITEM> patterns + FeaturePlaceHolderExpander expander(&library, &libItem, &linkItem); + return expander.ExpandVariables(format); +} + void cmComputeLinkInformation::AddImplicitLinkInfo() { // The link closure lists all languages whose implicit info is needed. @@ -610,7 +938,7 @@ void cmComputeLinkInformation::AddRuntimeLinkLibrary(std::string const& lang) std::vector<std::string> libsVec = cmExpandedList(*runtimeLinkOptions); for (std::string const& i : libsVec) { if (!cm::contains(this->ImplicitLinkLibs, i)) { - this->AddItem(i, nullptr); + this->AddItem({ i }); } } } @@ -625,7 +953,7 @@ void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang) std::vector<std::string> libsVec = cmExpandedList(*libs); for (std::string const& i : libsVec) { if (!cm::contains(this->ImplicitLinkLibs, i)) { - this->AddItem(i, nullptr); + this->AddItem({ i }); } } } @@ -639,10 +967,11 @@ void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang) } } -void cmComputeLinkInformation::AddItem(BT<std::string> const& item, - cmGeneratorTarget const* tgt, - ItemIsObject isObject) +void cmComputeLinkInformation::AddItem(LinkEntry const& entry) { + cmGeneratorTarget const* tgt = entry.Target; + BT<std::string> const& item = entry.Item; + // Compute the proper name to use to link this library. const std::string& config = this->Config; bool impexe = (tgt && tgt->IsExecutableWithExports()); @@ -657,28 +986,27 @@ void cmComputeLinkInformation::AddItem(BT<std::string> const& item, if (impexe && this->LoaderFlag) { // This link item is an executable that may provide symbols // used by this target. A special flag is needed on this - // platform. Add it now. - std::string linkItem = this->LoaderFlag; + // platform. Add it now using a special feature. cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config) ? cmStateEnums::ImportLibraryArtifact : cmStateEnums::RuntimeBinaryArtifact; - std::string exe = tgt->GetFullPath(config, artifact, true); - linkItem += exe; - this->Items.emplace_back(BT<std::string>(linkItem, item.Backtrace), - ItemIsPath::Yes, ItemIsObject::No, tgt); + this->Items.emplace_back( + BT<std::string>(exe, item.Backtrace), ItemIsPath::Yes, tgt, + this->FindLibraryFeature(entry.Feature == DEFAULT + ? "__CMAKE_LINK_EXECUTABLE" + : entry.Feature)); this->Depends.push_back(std::move(exe)); } else if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { // Add the interface library as an item so it can be considered as part // of COMPATIBLE_INTERFACE_ enforcement. The generators will ignore // this for the actual link line. - this->Items.emplace_back(std::string(), ItemIsPath::No, ItemIsObject::No, - tgt); + this->Items.emplace_back(std::string(), ItemIsPath::No, tgt); // Also add the item the interface specifies to be used in its place. std::string const& libName = tgt->GetImportedLibName(config); if (!libName.empty()) { - this->AddItem(BT<std::string>(libName, item.Backtrace), nullptr); + this->AddItem(BT<std::string>(libName, item.Backtrace)); } } else if (tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) { // Ignore object library! @@ -706,7 +1034,9 @@ void cmComputeLinkInformation::AddItem(BT<std::string> const& item, this->Depends.push_back(lib.Value); } - this->AddTargetItem(lib, tgt); + LinkEntry libEntry{ entry }; + libEntry.Item = lib; + this->AddTargetItem(libEntry); this->AddLibraryRuntimeInfo(lib.Value, tgt); if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY && this->Target->IsDLLPlatform()) { @@ -715,30 +1045,34 @@ void cmComputeLinkInformation::AddItem(BT<std::string> const& item, } } else { // This is not a CMake target. Use the name given. - if (cmSystemTools::FileIsFullPath(item.Value)) { - if (cmSystemTools::IsPathToFramework(item.Value) && - this->Makefile->IsOn("APPLE")) { - // This is a framework. - this->AddFrameworkItem(item.Value); - } else if (cmSystemTools::FileIsDirectory(item.Value)) { + if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s) || + (entry.Feature == DEFAULT && + cmSystemTools::IsPathToFramework(item.Value) && + this->Makefile->IsOn("APPLE"))) { + // This is a framework. + this->AddFrameworkItem(entry); + } else if (cmSystemTools::FileIsFullPath(item.Value)) { + if (cmSystemTools::FileIsDirectory(item.Value)) { // This is a directory. this->DropDirectoryItem(item); } else { // Use the full path given to the library file. this->Depends.push_back(item.Value); - this->AddFullItem(item, isObject); + this->AddFullItem(entry); this->AddLibraryRuntimeInfo(item.Value); } } else { // This is a library or option specified by the user. - this->AddUserItem(item, true); + this->AddUserItem(entry, true); } } } -void cmComputeLinkInformation::AddSharedDepItem(BT<std::string> const& item, - const cmGeneratorTarget* tgt) +void cmComputeLinkInformation::AddSharedDepItem(LinkEntry const& entry) { + BT<std::string> const& item = entry.Item; + const cmGeneratorTarget* tgt = entry.Target; + // Record dependencies on DLLs. if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY && this->Target->IsDLLPlatform() && @@ -776,7 +1110,7 @@ void cmComputeLinkInformation::AddSharedDepItem(BT<std::string> const& item, // If in linking mode, just link to the shared library. if (this->SharedDependencyMode == SharedDepModeLink) { - this->AddItem(item, tgt); + this->AddItem(entry); return; } @@ -1058,8 +1392,7 @@ void cmComputeLinkInformation::SetCurrentLinkType(LinkType lt) } } -void cmComputeLinkInformation::AddTargetItem(BT<std::string> const& item, - cmGeneratorTarget const* target) +void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry) { // This is called to handle a link item that is a full path to a target. // If the target is not a static library make sure the link type is @@ -1067,6 +1400,9 @@ void cmComputeLinkInformation::AddTargetItem(BT<std::string> const& item, // shared and static libraries but static-mode can handle only // static libraries. If a previous user item changed the link type // to static we need to make sure it is back to shared. + BT<std::string> const& item = entry.Item; + cmGeneratorTarget const* target = entry.Target; + if (target->GetType() != cmStateEnums::STATIC_LIBRARY) { this->SetCurrentLinkType(LinkShared); } @@ -1079,7 +1415,7 @@ void cmComputeLinkInformation::AddTargetItem(BT<std::string> const& item, // Handle case of an imported shared library with no soname. if (this->NoSONameUsesPath && target->IsImportedSharedLibWithoutSOName(this->Config)) { - this->AddSharedLibNoSOName(item.Value); + this->AddSharedLibNoSOName(entry); return; } @@ -1091,20 +1427,54 @@ void cmComputeLinkInformation::AddTargetItem(BT<std::string> const& item, this->OldLinkDirItems.push_back(item.Value); } - // Now add the full path to the library. - this->Items.emplace_back(item, ItemIsPath::Yes, ItemIsObject::No, target); + if (target->IsFrameworkOnApple() && this->GlobalGenerator->IsXcode() && + entry.Feature == DEFAULT) { + // ensure FRAMEWORK feature is loaded + this->AddLibraryFeature("FRAMEWORK"); + } + + if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s) && + target->IsFrameworkOnApple() && !this->GlobalGenerator->IsXcode()) { + // Add the framework directory and the framework item itself + auto fwItems = this->GlobalGenerator->SplitFrameworkPath(item.Value, true); + if (!fwItems) { + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Could not parse framework path \"", item.Value, + "\" linked by target ", this->Target->GetName(), '.'), + item.Backtrace); + return; + } + if (!fwItems->first.empty()) { + // Add the directory portion to the framework search path. + this->AddFrameworkPath(fwItems->first); + } + this->Items.emplace_back(fwItems->second, ItemIsPath::Yes, target, + this->FindLibraryFeature(entry.Feature)); + } else { + // Now add the full path to the library. + this->Items.emplace_back( + item, ItemIsPath::Yes, target, + this->FindLibraryFeature( + entry.Feature == DEFAULT + ? (target->IsFrameworkOnApple() && this->GlobalGenerator->IsXcode() + ? "FRAMEWORK" + : "__CMAKE_LINK_LIBRARY") + : entry.Feature)); + } } -void cmComputeLinkInformation::AddFullItem(BT<std::string> const& item, - ItemIsObject isObject) +void cmComputeLinkInformation::AddFullItem(LinkEntry const& entry) { + BT<std::string> const& item = entry.Item; + // Check for the implicit link directory special case. - if (this->CheckImplicitDirItem(item.Value)) { + if (this->CheckImplicitDirItem(entry)) { return; } // Check for case of shared library with no builtin soname. - if (this->NoSONameUsesPath && this->CheckSharedLibNoSOName(item.Value)) { + if (this->NoSONameUsesPath && this->CheckSharedLibNoSOName(entry)) { return; } @@ -1116,7 +1486,7 @@ void cmComputeLinkInformation::AddFullItem(BT<std::string> const& item, generator.find("Xcode") != std::string::npos)) { std::string file = cmSystemTools::GetFilenameName(item.Value); if (!this->ExtractAnyLibraryName.find(file)) { - this->HandleBadFullItem(item.Value, file); + this->HandleBadFullItem(entry, file); return; } } @@ -1147,11 +1517,18 @@ void cmComputeLinkInformation::AddFullItem(BT<std::string> const& item, } // Now add the full path to the library. - this->Items.emplace_back(item, ItemIsPath::Yes, isObject); + this->Items.emplace_back( + item, ItemIsPath::Yes, nullptr, + this->FindLibraryFeature( + entry.Feature == DEFAULT + ? (entry.IsObject ? "__CMAKE_LINK_OBJECT" : "__CMAKE_LINK_LIBRARY") + : entry.Feature)); } -bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item) +bool cmComputeLinkInformation::CheckImplicitDirItem(LinkEntry const& entry) { + BT<std::string> const& item = entry.Item; + // We only switch to a pathless item if the link type may be // enforced. Fortunately only platforms that support link types // seem to have magic per-architecture implicit link directories. @@ -1160,7 +1537,7 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item) } // Check if this item is in an implicit link directory. - std::string dir = cmSystemTools::GetFilenamePath(item); + std::string dir = cmSystemTools::GetFilenamePath(item.Value); if (!cm::contains(this->ImplicitLinkDirs, dir)) { // Only libraries in implicit link directories are converted to // pathless items. @@ -1169,7 +1546,7 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item) // Only apply the policy below if the library file is one that can // be found by the linker. - std::string file = cmSystemTools::GetFilenameName(item); + std::string file = cmSystemTools::GetFilenameName(item.Value); if (!this->ExtractAnyLibraryName.find(file)) { return false; } @@ -1179,10 +1556,10 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item) case cmPolicies::WARN: if (this->CMP0060Warn) { // Print the warning at most once for this item. - std::string const& wid = "CMP0060-WARNING-GIVEN-" + item; + std::string const& wid = "CMP0060-WARNING-GIVEN-" + item.Value; if (!this->CMakeInstance->GetPropertyAsBool(wid)) { this->CMakeInstance->SetProperty(wid, "1"); - this->CMP0060WarnItems.insert(item); + this->CMP0060WarnItems.insert(item.Value); } } CM_FALLTHROUGH; @@ -1200,15 +1577,17 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item) // directory then just report the file name without the directory // portion. This will allow the system linker to locate the proper // library for the architecture at link time. - this->AddUserItem(file, false); + LinkEntry fileEntry{ entry }; + fileEntry.Item = file; + this->AddUserItem(fileEntry, false); // Make sure the link directory ordering will find the library. - this->OrderLinkerSearchPath->AddLinkLibrary(item); + this->OrderLinkerSearchPath->AddLinkLibrary(item.Value); return true; } -void cmComputeLinkInformation::AddUserItem(BT<std::string> const& item, +void cmComputeLinkInformation::AddUserItem(LinkEntry const& entry, bool pathNotKnown) { // This is called to handle a link item that does not match a CMake @@ -1219,8 +1598,10 @@ void cmComputeLinkInformation::AddUserItem(BT<std::string> const& item, // foo ==> -lfoo // libfoo.a ==> -Wl,-Bstatic -lfoo - // Pass flags through untouched. + BT<std::string> const& item = entry.Item; + if (item.Value[0] == '-' || item.Value[0] == '$' || item.Value[0] == '`') { + // Pass flags through untouched. // if this is a -l option then we might need to warn about // CMP0003 so put it in OldUserFlagItems, if it is not a -l // or -Wl,-l (-framework -pthread), then allow it without a @@ -1305,9 +1686,20 @@ void cmComputeLinkInformation::AddUserItem(BT<std::string> const& item, } // Create an option to ask the linker to search for the library. - std::string out = cmStrCat(this->LibLinkFlag, lib, this->LibLinkSuffix); - this->Items.emplace_back(BT<std::string>(out, item.Backtrace), - ItemIsPath::No); + auto out = cmStrCat(this->LibLinkFlag, lib, this->LibLinkSuffix); + + if (entry.Feature != DEFAULT) { + auto const& feature = this->GetLibraryFeature(entry.Feature); + this->Items.emplace_back( + BT<std::string>( + feature.GetDecoratedItem(cmStrCat(lib, this->LibLinkSuffix), + item.Value, out, ItemIsPath::No), + item.Backtrace), + ItemIsPath::No); + } else { + this->Items.emplace_back(BT<std::string>(out, item.Backtrace), + ItemIsPath::No); + } // Here we could try to find the library the linker will find and // add a runtime information entry for it. It would probably not be @@ -1315,10 +1707,14 @@ void cmComputeLinkInformation::AddUserItem(BT<std::string> const& item, // specification. } -void cmComputeLinkInformation::AddFrameworkItem(std::string const& item) +void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry) { + std::string const& item = entry.Item.Value; + // Try to separate the framework name and path. - if (!this->SplitFramework.find(item)) { + auto fwItems = + this->GlobalGenerator->SplitFrameworkPath(item, entry.Feature != DEFAULT); + if (!fwItems) { std::ostringstream e; e << "Could not parse framework path \"" << item << "\" " << "linked by target " << this->Target->GetName() << "."; @@ -1326,26 +1722,36 @@ void cmComputeLinkInformation::AddFrameworkItem(std::string const& item) return; } - std::string fw_path = this->SplitFramework.match(1); - std::string fw = this->SplitFramework.match(2); - std::string full_fw = cmStrCat(fw_path, '/', fw, ".framework/", fw); + std::string fw_path = std::move(fwItems->first); + std::string fw = std::move(fwItems->second); + std::string full_fw = cmStrCat(fw, ".framework/", fw); - // Add the directory portion to the framework search path. - this->AddFrameworkPath(fw_path); + if (!fw_path.empty()) { + full_fw = cmStrCat(fw_path, '/', full_fw); + // Add the directory portion to the framework search path. + this->AddFrameworkPath(fw_path); + } // add runtime information this->AddLibraryRuntimeInfo(full_fw); + if (entry.Feature == DEFAULT) { + // ensure FRAMEWORK feature is loaded + this->AddLibraryFeature("FRAMEWORK"); + } + if (this->GlobalGenerator->IsXcode()) { // Add framework path - it will be handled by Xcode after it's added to // "Link Binary With Libraries" build phase - this->Items.emplace_back(item, ItemIsPath::Yes); + this->Items.emplace_back(item, ItemIsPath::Yes, nullptr, + this->FindLibraryFeature(entry.Feature == DEFAULT + ? "FRAMEWORK" + : entry.Feature)); } else { - // Add the item using the -framework option. - this->Items.emplace_back(std::string("-framework"), ItemIsPath::No); - cmOutputConverter converter(this->Makefile->GetStateSnapshot()); - fw = converter.EscapeForShell(fw); - this->Items.emplace_back(fw, ItemIsPath::No); + this->Items.emplace_back(fw, ItemIsPath::Yes, nullptr, + this->FindLibraryFeature(entry.Feature == DEFAULT + ? "FRAMEWORK" + : entry.Feature)); } } @@ -1355,10 +1761,10 @@ void cmComputeLinkInformation::DropDirectoryItem(BT<std::string> const& item) // user. this->CMakeInstance->IssueMessage( MessageType::WARNING, - cmStrCat( - "Target \"", this->Target->GetName(), - "\" requests linking to directory \"", item.Value, - "\". Targets may link only to libraries. CMake is dropping the item."), + cmStrCat("Target \"", this->Target->GetName(), + "\" requests linking to directory \"", item.Value, + "\". Targets may link only to libraries. CMake is dropping " + "the item."), item.Backtrace); } @@ -1378,9 +1784,6 @@ void cmComputeLinkInformation::ComputeFrameworkInfo() this->FrameworkPathsEmitted.insert(implicitDirVec.begin(), implicitDirVec.end()); - - // Regular expression to extract a framework path and name. - this->SplitFramework.compile("(.*)/(.*)\\.framework$"); } void cmComputeLinkInformation::AddFrameworkPath(std::string const& p) @@ -1390,42 +1793,44 @@ void cmComputeLinkInformation::AddFrameworkPath(std::string const& p) } } -bool cmComputeLinkInformation::CheckSharedLibNoSOName(std::string const& item) +bool cmComputeLinkInformation::CheckSharedLibNoSOName(LinkEntry const& entry) { // This platform will use the path to a library as its soname if the // library is given via path and was not built with an soname. If // this is a shared library that might be the case. - std::string file = cmSystemTools::GetFilenameName(item); + std::string file = cmSystemTools::GetFilenameName(entry.Item.Value); if (this->ExtractSharedLibraryName.find(file)) { // If we can guess the soname fairly reliably then assume the // library has one. Otherwise assume the library has no builtin // soname. std::string soname; - if (!cmSystemTools::GuessLibrarySOName(item, soname)) { - this->AddSharedLibNoSOName(item); + if (!cmSystemTools::GuessLibrarySOName(entry.Item.Value, soname)) { + this->AddSharedLibNoSOName(entry); return true; } } return false; } -void cmComputeLinkInformation::AddSharedLibNoSOName(std::string const& item) +void cmComputeLinkInformation::AddSharedLibNoSOName(LinkEntry const& entry) { // We have a full path to a shared library with no soname. We need // to ask the linker to locate the item because otherwise the path // we give to it will be embedded in the target linked. Then at // runtime the dynamic linker will search for the library using the // path instead of just the name. - std::string file = cmSystemTools::GetFilenameName(item); - this->AddUserItem(file, false); + LinkEntry fileEntry{ entry }; + fileEntry.Item = cmSystemTools::GetFilenameName(entry.Item.Value); + this->AddUserItem(fileEntry, false); // Make sure the link directory ordering will find the library. - this->OrderLinkerSearchPath->AddLinkLibrary(item); + this->OrderLinkerSearchPath->AddLinkLibrary(entry.Item.Value); } -void cmComputeLinkInformation::HandleBadFullItem(std::string const& item, +void cmComputeLinkInformation::HandleBadFullItem(LinkEntry const& entry, std::string const& file) { + std::string const& item = entry.Item.Value; // Do not depend on things that do not exist. auto i = std::find(this->Depends.begin(), this->Depends.end(), item); if (i != this->Depends.end()) { @@ -1435,7 +1840,9 @@ void cmComputeLinkInformation::HandleBadFullItem(std::string const& item, // Tell the linker to search for the item and provide the proper // path for it. Do not contribute to any CMP0003 warning (do not // put in OldLinkDirItems or OldUserFlagItems). - this->AddUserItem(file, false); + LinkEntry fileEntry{ entry }; + fileEntry.Item = file; + this->AddUserItem(fileEntry, false); this->OrderLinkerSearchPath->AddLinkLibrary(item); // Produce any needed message. @@ -1781,8 +2188,8 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, // Add directories explicitly specified by user std::string build_rpath; if (this->Target->GetBuildRPATH(this->Config, build_rpath)) { - // This will not resolve entries to use $ORIGIN, the user is expected to - // do that if necessary. + // This will not resolve entries to use $ORIGIN, the user is expected + // to do that if necessary. cmCLI_ExpandListUnique(build_rpath, runtimeDirs, emitted); } } diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 0315540..4b7fb1a 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> +#include <map> #include <memory> #include <set> #include <string> @@ -13,6 +14,7 @@ #include "cmsys/RegularExpression.hxx" +#include "cmComputeLinkDepends.h" #include "cmListFileCache.h" #include "cmValue.h" @@ -27,6 +29,9 @@ class cmake; */ class cmComputeLinkInformation { +private: + class FeatureDescriptor; + public: cmComputeLinkInformation(cmGeneratorTarget const* target, const std::string& config); @@ -42,28 +47,38 @@ public: Yes, }; - enum class ItemIsObject - { - No, - Yes, - }; - struct Item { - Item() = default; Item(BT<std::string> v, ItemIsPath isPath, - ItemIsObject isObject = ItemIsObject::No, - cmGeneratorTarget const* target = nullptr) + cmGeneratorTarget const* target = nullptr, + FeatureDescriptor const* feature = nullptr) : Value(std::move(v)) , IsPath(isPath) - , IsObject(isObject) , Target(target) + , Feature(feature) { } BT<std::string> Value; - ItemIsPath IsPath = ItemIsPath::Yes; - ItemIsObject IsObject = ItemIsObject::No; + ItemIsPath IsPath = ItemIsPath::No; cmGeneratorTarget const* Target = nullptr; + + bool HasFeature() const { return this->Feature != nullptr; } + const std::string& GetFeatureName() const + { + return HasFeature() ? this->Feature->Name + : cmComputeLinkDepends::LinkEntry::DEFAULT; + } + + BT<std::string> GetFormattedItem(std::string const& path) const + { + return { (this->Feature != nullptr) + ? this->Feature->GetDecoratedItem(path, this->IsPath) + : path, + Value.Backtrace }; + } + + private: + FeatureDescriptor const* Feature = nullptr; }; using ItemVector = std::vector<Item>; void AppendValues(std::string& result, std::vector<BT<std::string>>& values); @@ -104,10 +119,10 @@ public: const cmGeneratorTarget* GetTarget() { return this->Target; } private: - void AddItem(BT<std::string> const& item, const cmGeneratorTarget* tgt, - ItemIsObject isObject = ItemIsObject::No); - void AddSharedDepItem(BT<std::string> const& item, - cmGeneratorTarget const* tgt); + using LinkEntry = cmComputeLinkDepends::LinkEntry; + + void AddItem(LinkEntry const& entry); + void AddSharedDepItem(LinkEntry const& entry); void AddRuntimeDLL(cmGeneratorTarget const* tgt); // Output information. @@ -181,22 +196,20 @@ private: std::string NoCaseExpression(std::string const& str); // Handling of link items. - void AddTargetItem(BT<std::string> const& item, - const cmGeneratorTarget* target); - void AddFullItem(BT<std::string> const& item, ItemIsObject isObject); - bool CheckImplicitDirItem(std::string const& item); - void AddUserItem(BT<std::string> const& item, bool pathNotKnown); - void AddFrameworkItem(std::string const& item); + void AddTargetItem(LinkEntry const& entry); + void AddFullItem(LinkEntry const& entry); + bool CheckImplicitDirItem(LinkEntry const& entry); + void AddUserItem(LinkEntry const& entry, bool pathNotKnown); + void AddFrameworkItem(LinkEntry const& entry); void DropDirectoryItem(BT<std::string> const& item); - bool CheckSharedLibNoSOName(std::string const& item); - void AddSharedLibNoSOName(std::string const& item); - void HandleBadFullItem(std::string const& item, std::string const& file); + bool CheckSharedLibNoSOName(LinkEntry const& entry); + void AddSharedLibNoSOName(LinkEntry const& entry); + void HandleBadFullItem(LinkEntry const& entry, std::string const& file); // Framework info. void ComputeFrameworkInfo(); void AddFrameworkPath(std::string const& p); std::set<std::string> FrameworkPathsEmitted; - cmsys::RegularExpression SplitFramework; // Linker search path computation. std::unique_ptr<cmOrderDirectories> OrderLinkerSearchPath; @@ -237,4 +250,36 @@ private: void AddLibraryRuntimeInfo(std::string const& fullPath, const cmGeneratorTarget* target); void AddLibraryRuntimeInfo(std::string const& fullPath); + + class FeatureDescriptor + { + public: + FeatureDescriptor() = default; + FeatureDescriptor(std::string name, std::string itemFormat); + FeatureDescriptor(std::string name, std::string itemPathFormat, + std::string itemNameFormat); + FeatureDescriptor(std::string name, std::string prefix, + std::string itemPathFormat, std::string itemNameFormat, + std::string suffix); + + const std::string Name; + const bool Supported = false; + const std::string Prefix; + const std::string Suffix; + std::string GetDecoratedItem(std::string const& library, + ItemIsPath isPath) const; + std::string GetDecoratedItem(std::string const& library, + std::string const& linkItem, + std::string const& defaultValue, + ItemIsPath isPath) const; + + private: + std::string ItemPathFormat; + std::string ItemNameFormat; + }; + std::map<std::string, FeatureDescriptor> LibraryFeatureDescriptors; + bool AddLibraryFeature(std::string const& feature); + FeatureDescriptor const& GetLibraryFeature(std::string const& feature) const; + FeatureDescriptor const* FindLibraryFeature( + std::string const& feature) const; }; diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index b46b933..a21e614 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -934,13 +934,13 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os) // Isolate the file policy level. // Support CMake versions as far back as 2.6 but also support using NEW - // policy settings for up to CMake 3.21 (this upper limit may be reviewed + // policy settings for up to CMake 3.22 (this upper limit may be reviewed // and increased from time to time). This reduces the opportunity for CMake // warnings when an older export file is later used with newer CMake // versions. /* clang-format off */ os << "cmake_policy(PUSH)\n" - << "cmake_policy(VERSION 2.6...3.21)\n"; + << "cmake_policy(VERSION 2.6...3.22)\n"; /* clang-format on */ } diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index da2f15f..09e5015 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -15,6 +15,7 @@ #include <vector> #include <cm/memory> +#include <cm/optional> #include <cm/string_view> #include <cmext/algorithm> #include <cmext/string_view> @@ -1778,6 +1779,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, std::string userpwd; std::vector<std::string> curl_headers; + std::vector<std::pair<std::string, cm::optional<std::string>>> curl_ranges; while (i != args.end()) { if (*i == "TIMEOUT") { @@ -1890,6 +1892,27 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, return false; } curl_headers.push_back(*i); + } else if (*i == "RANGE_START") { + ++i; + if (i == args.end()) { + status.SetError("DOWNLOAD missing value for RANGE_START."); + return false; + } + curl_ranges.emplace_back(*i, cm::nullopt); + } else if (*i == "RANGE_END") { + ++i; + if (curl_ranges.empty()) { + curl_ranges.emplace_back("0", *i); + } else { + auto& last_range = curl_ranges.back(); + if (!last_range.second.has_value()) { + last_range.second = *i; + } else { + status.SetError("Multiple RANGE_END values is provided without " + "the corresponding RANGE_START."); + return false; + } + } } else if (file.empty()) { file = *i; } else { @@ -1899,6 +1922,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, } ++i; } + // Can't calculate hash if we don't save the file. // TODO Incrementally calculate hash in the write callback as the file is // being downloaded so this check can be relaxed. @@ -1984,6 +2008,13 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, check_curl_result(res, "DOWNLOAD cannot set TLS/SSL Verify off: "); } + for (const auto& range : curl_ranges) { + std::string curl_range = range.first + '-' + + (range.second.has_value() ? range.second.value() : ""); + res = ::curl_easy_setopt(curl, CURLOPT_RANGE, curl_range.c_str()); + check_curl_result(res, "DOWNLOAD cannot set range: "); + } + // check to see if a CAINFO file has been specified // command arg comes first std::string const& cainfo_err = cmCurlSetCAInfo(curl, cainfo); diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index d4b02a5..d35d428 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -167,7 +167,7 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const cm::string_view property(this->Top()->Property); return property == "LINK_DIRECTORIES"_s || property == "LINK_OPTIONS"_s || - property == "LINK_DEPENDS"_s; + property == "LINK_DEPENDS"_s || property == "LINK_LIBRARY_OVERRIDE"_s; } bool cmGeneratorExpressionDAGChecker::EvaluatingLinkOptionsExpression() const diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 396e9c9..b63b90b 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -1198,6 +1198,68 @@ static const struct LinkLanguageAndIdNode : public cmGeneratorExpressionNode } } linkLanguageAndIdNode; +static const struct LinkLibraryNode : public cmGeneratorExpressionNode +{ + LinkLibraryNode() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return OneOrMoreParameters; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* dagChecker) const override + { + if (!context->HeadTarget || !dagChecker || + !dagChecker->EvaluatingLinkLibraries()) { + reportError(context, content->GetOriginalExpression(), + "$<LINK_LIBRARY:...> may only be used with binary targets " + "to specify link libraries."); + return std::string(); + } + + std::vector<std::string> list; + cmExpandLists(parameters.begin(), parameters.end(), list); + if (list.empty()) { + reportError( + context, content->GetOriginalExpression(), + "$<LINK_LIBRARY:...> expects a feature name as first argument."); + return std::string(); + } + if (list.size() == 1) { + // no libraries specified, ignore this genex + return std::string(); + } + + auto const& feature = list.front(); + const auto LL_BEGIN = cmStrCat("<LINK_LIBRARY:", feature, '>'); + const auto LL_END = cmStrCat("</LINK_LIBRARY:", feature, '>'); + + // filter out $<LINK_LIBRARY:..> tags with same feature + // and raise an error for any different feature + cm::erase_if(list, [&](const std::string& item) -> bool { + return item == LL_BEGIN || item == LL_END; + }); + auto it = + std::find_if(list.cbegin() + 1, list.cend(), + [&feature](const std::string& item) -> bool { + return cmHasPrefix(item, "<LINK_LIBRARY:"_s) && + item.substr(14, item.find('>', 14) - 14) != feature; + }); + if (it != list.cend()) { + reportError( + context, content->GetOriginalExpression(), + "$<LINK_LIBRARY:...> with different features cannot be nested."); + return std::string(); + } + + list.front() = LL_BEGIN; + list.push_back(LL_END); + + return cmJoin(list, ";"_s); + } +} linkLibraryNode; + static const struct HostLinkNode : public cmGeneratorExpressionNode { HostLinkNode() {} // NOLINT(modernize-use-equals-default) @@ -2668,6 +2730,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "COMPILE_LANGUAGE", &languageNode }, { "LINK_LANG_AND_ID", &linkLanguageAndIdNode }, { "LINK_LANGUAGE", &linkLanguageNode }, + { "LINK_LIBRARY", &linkLibraryNode }, { "HOST_LINK", &hostLinkNode }, { "DEVICE_LINK", &deviceLinkNode }, { "SHELL_PATH", &shellPathNode } diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 9f1029e..e722fa9 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -2047,7 +2047,11 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, } else if (ext == "appxmanifest") { kind = SourceKindAppManifest; } else if (ext == "manifest") { - kind = SourceKindManifest; + if (sf->GetPropertyAsBool("VS_DEPLOYMENT_CONTENT")) { + kind = SourceKindExtra; + } else { + kind = SourceKindManifest; + } } else if (ext == "pfx") { kind = SourceKindCertificate; } else if (ext == "xaml") { @@ -4625,7 +4629,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( } std::vector<BT<std::string>>& cmGeneratorTarget::ResolveLinkerWrapper( - std::vector<BT<std::string>>& result, const std::string& language) const + std::vector<BT<std::string>>& result, const std::string& language, + bool joinItems) const { // replace "LINKER:" prefixed elements by actual linker wrapper const std::string wrapper(this->Makefile->GetSafeDefinition( @@ -4684,7 +4689,14 @@ std::vector<BT<std::string>>& cmGeneratorTarget::ResolveLinkerWrapper( std::vector<BT<std::string>> options = wrapOptions( linkerOptions, bt, wrapperFlag, wrapperSep, concatFlagAndArgs); - result.insert(entry, options.begin(), options.end()); + if (joinItems) { + result.insert(entry, + cmJoin(cmRange<decltype(options.cbegin())>( + options.cbegin(), options.cend()), + " "_s)); + } else { + result.insert(entry, options.begin(), options.end()); + } } return result; } @@ -6377,7 +6389,8 @@ bool cmGeneratorTarget::VerifyLinkItemIsTarget(LinkItemRole role, std::string const& str = item.AsStr(); if (!str.empty() && (str[0] == '-' || str[0] == '$' || str[0] == '`' || - str.find_first_of("/\\") != std::string::npos)) { + str.find_first_of("/\\") != std::string::npos || + cmHasPrefix(str, "<LINK_LIBRARY:"_s))) { return true; } diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 45639c0..3e30913 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -513,7 +513,8 @@ public: std::string const& config, std::string const& language) const; std::vector<BT<std::string>>& ResolveLinkerWrapper( - std::vector<BT<std::string>>& result, const std::string& language) const; + std::vector<BT<std::string>>& result, const std::string& language, + bool joinItems = false) const; void GetStaticLibraryLinkOptions(std::vector<std::string>& result, const std::string& config, diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 156ecce..baa54e5 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -19,6 +19,7 @@ #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" +#include "cmsys/RegularExpression.hxx" #if defined(_WIN32) && !defined(__CYGWIN__) # include <windows.h> @@ -2522,6 +2523,47 @@ bool cmGlobalGenerator::NameResolvesToFramework( return false; } +// If the file has no extension it's either a raw executable or might +// be a direct reference to a binary within a framework (bad practice!). +// This is where we change the path to point to the framework directory. +// .tbd files also can be located in SDK frameworks (they are +// placeholders for actual libraries shipped with the OS) +cm::optional<std::pair<std::string, std::string>> +cmGlobalGenerator::SplitFrameworkPath(const std::string& path, + bool extendedFormat) const +{ + // Check for framework structure: + // (/path/to/)?FwName.framework + // or (/path/to/)?FwName.framework/FwName(.tbd)? + // or (/path/to/)?FwName.framework/Versions/*/FwName(.tbd)? + static cmsys::RegularExpression frameworkPath( + "((.+)/)?(.+)\\.framework(/Versions/[^/]+)?(/(.+))?$"); + + auto ext = cmSystemTools::GetFilenameLastExtension(path); + if ((ext.empty() || ext == ".tbd" || ext == ".framework") && + frameworkPath.find(path)) { + auto name = frameworkPath.match(3); + auto libname = + cmSystemTools::GetFilenameWithoutExtension(frameworkPath.match(6)); + if (!libname.empty() && name != libname) { + return cm::nullopt; + } + return std::pair<std::string, std::string>{ frameworkPath.match(2), name }; + } + + if (extendedFormat) { + // path format can be more flexible: (/path/to/)?fwName(.framework)? + auto fwDir = cmSystemTools::GetParentDirectory(path); + auto name = cmSystemTools::GetFilenameLastExtension(path) == ".framework" + ? cmSystemTools::GetFilenameWithoutExtension(path) + : cmSystemTools::GetFilenameName(path); + + return std::pair<std::string, std::string>{ fwDir, name }; + } + + return cm::nullopt; +} + bool cmGlobalGenerator::CheckCMP0037(std::string const& targetName, std::string const& reason) const { diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index a43d4a6..a4b2ae3 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -367,6 +367,13 @@ public: /** Determine if a name resolves to a framework on disk or a built target that is a framework. */ bool NameResolvesToFramework(const std::string& libname) const; + /** Split a framework path to the directory and name of the framework + * returns std::nullopt if the path does not match with framework format + * when extendedFormat is true, required format is relaxed (i.e. extension + * `.framework' is optional). Used when FRAMEWORK link feature is + * specified */ + cm::optional<std::pair<std::string, std::string>> SplitFrameworkPath( + const std::string& path, bool extendedFormat = false) const; cmMakefile* FindMakefile(const std::string& start_dir) const; cmLocalGenerator* FindLocalGenerator(cmDirectoryId const& id) const; diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index db54b86..28d6295 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -1286,6 +1286,13 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand( return makeCommands; } +bool cmGlobalVisualStudio10Generator::IsInSolution( + const cmGeneratorTarget* gt) const +{ + return gt->IsInBuildSystem() && + gt->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET; +} + bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf) { if (this->DefaultPlatformToolset == "v100") { diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index 4977a84..2203f71 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -118,6 +118,8 @@ public: return this->WindowsTargetPlatformVersion; } + bool IsInSolution(const cmGeneratorTarget* gt) const override; + /** Return true if building for WindowsCE */ bool TargetsWindowsCE() const override { return this->SystemIsWindowsCE; } diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 134937e..1c10fb3 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -359,7 +359,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetConfigurations( // loop over again and write out configurations for each target // in the solution for (cmGeneratorTarget const* target : projectTargets) { - if (!target->IsInBuildSystem()) { + if (!this->IsInSolution(target)) { continue; } cmValue expath = target->GetProperty("EXTERNAL_MSPROJECT"); @@ -396,7 +396,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( VisualStudioFolders.clear(); for (cmGeneratorTarget const* target : projectTargets) { - if (!target->IsInBuildSystem()) { + if (!this->IsInSolution(target)) { continue; } bool written = false; @@ -458,22 +458,6 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( } } -void cmGlobalVisualStudio7Generator::WriteTargetDepends( - std::ostream& fout, OrderedTargetDependSet const& projectTargets) -{ - for (cmGeneratorTarget const* target : projectTargets) { - if (!target->IsInBuildSystem()) { - continue; - } - cmValue vcprojName = target->GetProperty("GENERATOR_FILE_NAME"); - if (vcprojName) { - std::string dir = - target->GetLocalGenerator()->GetCurrentSourceDirectory(); - this->WriteProjectDepends(fout, *vcprojName, dir, target); - } - } -} - void cmGlobalVisualStudio7Generator::WriteFolders(std::ostream& fout) { cm::string_view const prefix = "CMAKE_FOLDER_GUID_"; diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h index 33f1063..a55cf45 100644 --- a/Source/cmGlobalVisualStudio7Generator.h +++ b/Source/cmGlobalVisualStudio7Generator.h @@ -148,8 +148,6 @@ protected: virtual void WriteTargetsToSolution( std::ostream& fout, cmLocalGenerator* root, OrderedTargetDependSet const& projectTargets); - virtual void WriteTargetDepends( - std::ostream& fout, OrderedTargetDependSet const& projectTargets); virtual void WriteTargetConfigurations( std::ostream& fout, std::vector<std::string> const& configs, OrderedTargetDependSet const& projectTargets); diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index dbd2de9..323ee67 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -392,7 +392,7 @@ void cmGlobalVisualStudio8Generator::WriteProjectDepends( TargetDependSet const& unordered = this->GetTargetDirectDepends(gt); OrderedTargetDependSet depends(unordered, std::string()); for (cmTargetDepend const& i : depends) { - if (!i->IsInBuildSystem()) { + if (!this->IsInSolution(i)) { continue; } std::string guid = this->GetGUID(i->GetName()); diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 141b5eb..cddaaa4 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -837,6 +837,12 @@ bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly( return languages.size() == 1 && *languages.begin() == "Fortran"; } +bool cmGlobalVisualStudioGenerator::IsInSolution( + const cmGeneratorTarget* gt) const +{ + return gt->IsInBuildSystem(); +} + bool cmGlobalVisualStudioGenerator::TargetCompare::operator()( cmGeneratorTarget const* l, cmGeneratorTarget const* r) const { diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index cb1b14b..4f5f100 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -98,6 +98,9 @@ public: // return true if target is fortran only bool TargetIsFortranOnly(const cmGeneratorTarget* gt); + // return true if target should be included in solution. + virtual bool IsInSolution(const cmGeneratorTarget* gt) const; + /** Get the top-level registry key for this VS version. */ std::string GetRegistryBase(); diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 203addd..b752c41 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1154,47 +1154,25 @@ std::string GetSourcecodeValueFromFileExtension( return sourcecode; } -// If the file has no extension it's either a raw executable or might -// be a direct reference to a binary within a framework (bad practice!). -// This is where we change the path to point to the framework directory. -// .tbd files also can be located in SDK frameworks (they are -// placeholders for actual libraries shipped with the OS) -std::string GetLibraryOrFrameworkPath(const std::string& path) +} // anonymous + +// Extracts the framework directory, if path matches the framework syntax +// otherwise returns the path untouched +std::string cmGlobalXCodeGenerator::GetLibraryOrFrameworkPath( + const std::string& path) const { - auto ext = cmSystemTools::GetFilenameLastExtension(path); - if (ext.empty() || ext == ".tbd") { - auto name = cmSystemTools::GetFilenameWithoutExtension(path); - // Check for iOS framework structure: - // FwName.framework/FwName (and also on macOS where FwName lib is a - // symlink) - auto parentDir = cmSystemTools::GetParentDirectory(path); - auto parentName = cmSystemTools::GetFilenameWithoutExtension(parentDir); - ext = cmSystemTools::GetFilenameLastExtension(parentDir); - if (ext == ".framework" && name == parentName) { - return parentDir; - } - // Check for macOS framework structure: - // FwName.framework/Versions/*/FwName - std::vector<std::string> components; - cmSystemTools::SplitPath(path, components); - if (components.size() > 3 && - components[components.size() - 3] == "Versions") { - ext = cmSystemTools::GetFilenameLastExtension( - components[components.size() - 4]); - parentName = cmSystemTools::GetFilenameWithoutExtension( - components[components.size() - 4]); - if (ext == ".framework" && name == parentName) { - components.erase(components.begin() + components.size() - 3, - components.end()); - return cmSystemTools::JoinPath(components); - } + auto fwItems = this->SplitFrameworkPath(path); + if (fwItems) { + if (fwItems->first.empty()) { + return cmStrCat(fwItems->second, ".framework"); + } else { + return cmStrCat(fwItems->first, '/', fwItems->second, ".framework"); } } + return path; } -} // anonymous - cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath( const std::string& fullpath, cmGeneratorTarget* target, const std::string& lang, cmSourceFile* sf) @@ -1217,7 +1195,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath( ext = ext.substr(1); } if (fileType.empty()) { - path = GetLibraryOrFrameworkPath(path); + path = this->GetLibraryOrFrameworkPath(path); ext = cmSystemTools::GetFilenameLastExtension(path); if (!ext.empty()) { ext = ext.substr(1); @@ -3541,13 +3519,14 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) } else { linkDir = libItem->Value.Value; } - linkDir = GetLibraryOrFrameworkPath(linkDir); - bool isFramework = cmSystemTools::IsPathToFramework(linkDir); - linkDir = cmSystemTools::GetParentDirectory(linkDir); - if (isFramework) { - if (std::find(frameworkSearchPaths.begin(), frameworkSearchPaths.end(), - linkDir) == frameworkSearchPaths.end()) { - frameworkSearchPaths.push_back(linkDir); + if (cmHasSuffix(libItem->GetFeatureName(), "FRAMEWORK"_s)) { + auto fwItems = this->SplitFrameworkPath(linkDir, true); + if (fwItems && !fwItems->first.empty()) { + linkDir = std::move(fwItems->first); + if (std::find(frameworkSearchPaths.begin(), frameworkSearchPaths.end(), + linkDir) == frameworkSearchPaths.end()) { + frameworkSearchPaths.push_back(linkDir); + } } } else { if (std::find(linkSearchPaths.begin(), linkSearchPaths.end(), linkDir) == @@ -3555,7 +3534,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) linkSearchPaths.push_back(linkDir); } } - // Add target dependency + if (libItem->Target && !libItem->Target->IsImported()) { for (auto const& configName : this->CurrentConfigurationTypes) { target->AddDependTarget(configName, libItem->Target->GetName()); @@ -3729,22 +3708,27 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) if (cmSystemTools::FileIsFullPath(cleanPath)) { cleanPath = cmSystemTools::CollapseFullPath(cleanPath); } - const auto libPath = GetLibraryOrFrameworkPath(cleanPath); - if (cmSystemTools::StringEndsWith(libPath.c_str(), ".framework")) { - const auto fwName = - cmSystemTools::GetFilenameWithoutExtension(libPath); - const auto fwDir = cmSystemTools::GetParentDirectory(libPath); - if (emitted.insert(fwDir).second) { - // This is a search path we had not added before and it isn't an - // implicit search path, so we need it - libPaths.Add("-F " + this->XCodeEscapePath(fwDir)); + bool isFramework = + cmHasSuffix(libName.GetFeatureName(), "FRAMEWORK"_s); + if (isFramework) { + const auto fwItems = + this->SplitFrameworkPath(cleanPath, isFramework); + if (!fwItems->first.empty() && + emitted.insert(fwItems->first).second) { + // This is a search path we had not added before and it isn't + // an implicit search path, so we need it + libPaths.Add("-F " + this->XCodeEscapePath(fwItems->first)); } - libPaths.Add("-framework " + this->XCodeEscapePath(fwName)); + libPaths.Add( + libName.GetFormattedItem(this->XCodeEscapePath(fwItems->second)) + .Value); } else { - libPaths.Add(this->XCodeEscapePath(cleanPath)); + libPaths.Add( + libName.GetFormattedItem(this->XCodeEscapePath(cleanPath)) + .Value); } if ((!libName.Target || libName.Target->IsImported()) && - IsLinkPhaseLibraryExtension(libPath)) { + (isFramework || IsLinkPhaseLibraryExtension(cleanPath))) { // Create file reference for embedding auto it = this->ExternalLibRefs.find(cleanPath); if (it == this->ExternalLibRefs.end()) { @@ -3912,8 +3896,8 @@ void cmGlobalXCodeGenerator::AddEmbeddedFrameworks(cmXCodeObject* target) { static const auto dstSubfolderSpec = "10"; - // Despite the name, by default Xcode uses "Embed Frameworks" build phase for - // both frameworks and dynamic libraries + // Despite the name, by default Xcode uses "Embed Frameworks" build phase + // for both frameworks and dynamic libraries this->AddEmbeddedObjects(target, "Embed Frameworks", "XCODE_EMBED_FRAMEWORKS", dstSubfolderSpec, NoActionOnCopyByDefault); diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index ff6ffe8..98cebef 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -330,6 +330,8 @@ private: { } + std::string GetLibraryOrFrameworkPath(const std::string& path) const; + std::string GetObjectsDirectory(const std::string& projName, const std::string& configName, const cmGeneratorTarget* t, diff --git a/Source/cmLinkLibrariesCommand.cxx b/Source/cmLinkLibrariesCommand.cxx index 2b8f836..ed89e91 100644 --- a/Source/cmLinkLibrariesCommand.cxx +++ b/Source/cmLinkLibrariesCommand.cxx @@ -35,5 +35,7 @@ bool cmLinkLibrariesCommand(std::vector<std::string> const& args, mf.AppendProperty("LINK_LIBRARIES", *i); } + mf.CheckProperty("LINK_LIBRARIES"); + return true; } diff --git a/Source/cmLinkLineComputer.cxx b/Source/cmLinkLineComputer.cxx index 5646368..290642b 100644 --- a/Source/cmLinkLineComputer.cxx +++ b/Source/cmLinkLineComputer.cxx @@ -75,14 +75,8 @@ void cmLinkLineComputer::ComputeLinkLibs( BT<std::string> linkLib; if (item.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) { - if (item.IsObject == cmComputeLinkInformation::ItemIsObject::Yes) { - linkLib.Value += cli.GetObjLinkFileFlag(); - } else { - linkLib.Value += cli.GetLibLinkFileFlag(); - } - linkLib.Value += this->ConvertToOutputFormat( - this->ConvertToLinkReference(item.Value.Value)); - linkLib.Backtrace = item.Value.Backtrace; + linkLib = item.GetFormattedItem(this->ConvertToOutputFormat( + this->ConvertToLinkReference(item.Value.Value))); } else { linkLib = item.Value; } diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx index 43f161b..71f9f80 100644 --- a/Source/cmLinkLineDeviceComputer.cxx +++ b/Source/cmLinkLineDeviceComputer.cxx @@ -118,8 +118,10 @@ void cmLinkLineDeviceComputer::ComputeLinkLibraries( // can tolerate '.so' or '.dylib' it cannot tolerate '.so.1'. if (cmHasLiteralSuffix(item.Value.Value, ".a") || cmHasLiteralSuffix(item.Value.Value, ".lib")) { - linkLib.Value += this->ConvertToOutputFormat( - this->ConvertToLinkReference(item.Value.Value)); + linkLib.Value = item + .GetFormattedItem(this->ConvertToOutputFormat( + this->ConvertToLinkReference(item.Value.Value))) + .Value; } } else if (item.Value == "-framework") { // This is the first part of '-framework Name' where the framework @@ -127,7 +129,7 @@ void cmLinkLineDeviceComputer::ComputeLinkLibraries( skipItemAfterFramework = true; continue; } else if (cmLinkItemValidForDevice(item.Value.Value)) { - linkLib.Value += item.Value.Value; + linkLib.Value = item.Value.Value; } if (emitted.insert(linkLib.Value).second) { diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 3da266d..b90af08 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -40,6 +40,7 @@ struct cmListFileParser cmListFileLexer* Lexer; std::string FunctionName; long FunctionLine; + long FunctionLineEnd; std::vector<cmListFileArgument> FunctionArguments; enum { @@ -146,7 +147,7 @@ bool cmListFileParser::Parse() if (this->ParseFunction(token->text, token->line)) { this->ListFile->Functions.emplace_back( std::move(this->FunctionName), this->FunctionLine, - std::move(this->FunctionArguments)); + this->FunctionLineEnd, std::move(this->FunctionArguments)); } else { return false; } @@ -259,6 +260,7 @@ bool cmListFileParser::ParseFunction(const char* name, long line) } } else if (token->type == cmListFileLexer_Token_ParenRight) { if (parenDepth == 0) { + this->FunctionLineEnd = token->line; return true; } parenDepth--; @@ -539,11 +541,11 @@ std::ostream& operator<<(std::ostream& os, BT<std::string> const& s) return os << s.Value; } -std::vector<BT<std::string>> ExpandListWithBacktrace( - std::string const& list, cmListFileBacktrace const& bt) +std::vector<BT<std::string>> cmExpandListWithBacktrace( + std::string const& list, cmListFileBacktrace const& bt, bool emptyArgs) { std::vector<BT<std::string>> result; - std::vector<std::string> tmp = cmExpandedList(list); + std::vector<std::string> tmp = cmExpandedList(list, emptyArgs); result.reserve(tmp.size()); for (std::string& i : tmp) { result.emplace_back(std::move(i), bt); diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index 5d45027..c3da81b 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -51,9 +51,9 @@ struct cmListFileArgument class cmListFileFunction { public: - cmListFileFunction(std::string name, long line, + cmListFileFunction(std::string name, long line, long lineEnd, std::vector<cmListFileArgument> args) - : Impl{ std::make_shared<Implementation>(std::move(name), line, + : Impl{ std::make_shared<Implementation>(std::move(name), line, lineEnd, std::move(args)) } { } @@ -69,6 +69,7 @@ public: } long Line() const noexcept { return this->Impl->Line; } + long LineEnd() const noexcept { return this->Impl->LineEnd; } std::vector<cmListFileArgument> const& Arguments() const noexcept { @@ -78,11 +79,12 @@ public: private: struct Implementation { - Implementation(std::string name, long line, + Implementation(std::string name, long line, long lineEnd, std::vector<cmListFileArgument> args) : OriginalName{ std::move(name) } , LowerCaseName{ cmSystemTools::LowerCase(this->OriginalName) } , Line{ line } + , LineEnd{ lineEnd } , Arguments{ std::move(args) } { } @@ -90,6 +92,7 @@ private: std::string OriginalName; std::string LowerCaseName; long Line = 0; + long LineEnd = 0; std::vector<cmListFileArgument> Arguments; }; @@ -230,9 +233,10 @@ public: friend bool operator==(T const& l, BTs<T> const& r) { return l == r.Value; } }; -std::vector<BT<std::string>> ExpandListWithBacktrace( +std::vector<BT<std::string>> cmExpandListWithBacktrace( std::string const& list, - cmListFileBacktrace const& bt = cmListFileBacktrace()); + cmListFileBacktrace const& bt = cmListFileBacktrace(), + bool emptyArgs = false); struct cmListFile { diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 2adb232..3976c42 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -3199,7 +3199,7 @@ void cmLocalGenerator::AppendDefines(std::set<std::string>& defines, std::string const& defines_list) const { std::set<BT<std::string>> tmp; - this->AppendDefines(tmp, ExpandListWithBacktrace(defines_list)); + this->AppendDefines(tmp, cmExpandListWithBacktrace(defines_list)); for (BT<std::string> const& i : tmp) { defines.emplace(i.Value); } @@ -3214,7 +3214,7 @@ void cmLocalGenerator::AppendDefines(std::set<BT<std::string>>& defines, } // Expand the list of definitions. - this->AppendDefines(defines, ExpandListWithBacktrace(defines_list)); + this->AppendDefines(defines, cmExpandListWithBacktrace(defines_list)); } void cmLocalGenerator::AppendDefines( diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index ed7e888..f65add1 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -1294,7 +1294,9 @@ void cmLocalVisualStudio7GeneratorInternals::OutputLibraries( for (auto const& lib : libs) { if (lib.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) { std::string rel = lg->MaybeRelativeToCurBinDir(lib.Value.Value); - fout << lg->ConvertToXMLOutputPath(rel) << " "; + rel = lg->ConvertToXMLOutputPath(rel); + fout << (lib.HasFeature() ? lib.GetFormattedItem(rel).Value : rel) + << " "; } else if (!lib.Target || lib.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { fout << lib.Value.Value << " "; diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index 93f01ed..2703c7b 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -252,7 +252,7 @@ std::string cmLocalVisualStudioGenerator::FinishConstructScript( // Store the script in a string. std::string script; - if (useLocal && projectType == VsProjectType::csproj) { + if (useLocal && projectType != VsProjectType::vcxproj) { // This label is not provided by MSBuild for C# projects. script += newline; script += this->GetReportErrorLabel(); diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index 154df63..ef12487 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -116,7 +116,7 @@ bool cmMacroHelperCommand::operator()( newLFFArgs.push_back(std::move(arg)); } cmListFileFunction newLFF{ func.OriginalName(), func.Line(), - std::move(newLFFArgs) }; + func.LineEnd(), std::move(newLFFArgs) }; cmExecutionStatus status(makefile); if (!makefile.ExecuteCommand(newLFF, status) || status.GetNestedError()) { // The error message should have already included the call stack diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 94d3be6..6a5d518 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -291,6 +291,9 @@ void cmMakefile::PrintCommandTrace( builder["indentation"] = ""; val["file"] = full_path; val["line"] = static_cast<Json::Value::Int64>(lff.Line()); + if (lff.Line() != lff.LineEnd()) { + val["line_end"] = static_cast<Json::Value::Int64>(lff.LineEnd()); + } if (deferId) { val["defer"] = *deferId; } @@ -302,6 +305,8 @@ void cmMakefile::PrintCommandTrace( val["time"] = cmSystemTools::GetTime(); val["frame"] = static_cast<Json::Value::UInt64>(this->ExecutionStatusStack.size()); + val["global_frame"] = + static_cast<Json::Value::UInt64>(this->RecursionDepth); msg << Json::writeString(builder, val); #endif break; @@ -1663,6 +1668,7 @@ void cmMakefile::Configure() this->Backtrace); cmListFileFunction project{ "project", 0, + 0, { { "Project", cmListFileArgument::Unquoted, 0 }, { "__CMAKE_INJECTED_PROJECT_COMMAND__", @@ -3976,6 +3982,31 @@ std::vector<std::string> cmMakefile::GetPropertyKeys() const return this->StateSnapshot.GetDirectory().GetPropertyKeys(); } +void cmMakefile::CheckProperty(const std::string& prop) const +{ + // Certain properties need checking. + if (prop == "LINK_LIBRARIES") { + if (cmValue value = this->GetProperty(prop)) { + // Look for <LINK_LIBRARY:> internal pattern + static cmsys::RegularExpression linkLibrary( + "(^|;)(</?LINK_LIBRARY:[^;>]*>)(;|$)"); + if (!linkLibrary.find(value)) { + return; + } + + // Report an error. + this->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat( + "Property ", prop, " contains the invalid item \"", + linkLibrary.match(2), "\". The ", prop, + " property may contain the generator-expression " + "\"$<LINK_LIBRARY:...>\" " + "which may be used to specify how the libraries are linked.")); + } + } +} + cmTarget* cmMakefile::FindLocalNonAliasTarget(const std::string& name) const { auto i = this->Targets.find(name); @@ -4395,12 +4426,14 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id, } // Deprecate old policies. - if (status == cmPolicies::OLD && id <= cmPolicies::CMP0094 && + if (status == cmPolicies::OLD && id <= cmPolicies::CMP0097 && !(this->GetCMakeInstance()->GetIsInTryCompile() && ( // Policies set by cmCoreTryCompile::TryCompileCode. id == cmPolicies::CMP0065 || id == cmPolicies::CMP0083 || - id == cmPolicies::CMP0091))) { + id == cmPolicies::CMP0091)) && + (!this->IsSet("CMAKE_WARN_DEPRECATED") || + this->IsOn("CMAKE_WARN_DEPRECATED"))) { this->IssueMessage(MessageType::DEPRECATION_WARNING, cmPolicies::GetPolicyDeprecatedWarning(id)); } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index f425697..ad8a014 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -787,6 +787,7 @@ public: cmValue GetProperty(const std::string& prop, bool chain) const; bool GetPropertyAsBool(const std::string& prop) const; std::vector<std::string> GetPropertyKeys() const; + void CheckProperty(const std::string& prop) const; //! Initialize a makefile from its parent void InitializeFromParent(cmMakefile* parent); diff --git a/Source/cmPlaceholderExpander.cxx b/Source/cmPlaceholderExpander.cxx new file mode 100644 index 0000000..118017e --- /dev/null +++ b/Source/cmPlaceholderExpander.cxx @@ -0,0 +1,54 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmPlaceholderExpander.h" + +#include <cctype> + +std::string& cmPlaceholderExpander::ExpandVariables(std::string& s) +{ + std::string::size_type start = s.find('<'); + // no variables to expand + if (start == std::string::npos) { + return s; + } + std::string::size_type pos = 0; + std::string expandedInput; + while (start != std::string::npos && start < s.size() - 2) { + std::string::size_type end = s.find('>', start); + // if we find a < with no > we are done + if (end == std::string::npos) { + s = expandedInput; + return s; + } + char c = s[start + 1]; + // if the next char after the < is not A-Za-z then + // skip it and try to find the next < in the string + if (!isalpha(c)) { + start = s.find('<', start + 1); + } else { + // extract the var + std::string var = s.substr(start + 1, end - start - 1); + std::string replace = this->ExpandVariable(var); + expandedInput += s.substr(pos, start - pos); + + // Prevent consecutive whitespace in the output if the rule variable + // expands to an empty string. + bool consecutive = replace.empty() && start > 0 && s[start - 1] == ' ' && + end + 1 < s.size() && s[end + 1] == ' '; + if (consecutive) { + expandedInput.pop_back(); + } + + expandedInput += replace; + + // move to next one + start = s.find('<', start + var.size() + 2); + pos = end + 1; + } + } + // add the rest of the input + expandedInput += s.substr(pos, s.size() - pos); + s = expandedInput; + + return s; +} diff --git a/Source/cmPlaceholderExpander.h b/Source/cmPlaceholderExpander.h new file mode 100644 index 0000000..24225cc --- /dev/null +++ b/Source/cmPlaceholderExpander.h @@ -0,0 +1,19 @@ +/* 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 <string> + +class cmPlaceholderExpander +{ +public: + virtual ~cmPlaceholderExpander() = default; + + std::string& ExpandVariables(std::string& string); + +protected: + virtual std::string ExpandVariable(std::string const& variable) = 0; +}; diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx index 4cee09d..b63d11c 100644 --- a/Source/cmRulePlaceholderExpander.cxx +++ b/Source/cmRulePlaceholderExpander.cxx @@ -2,7 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmRulePlaceholderExpander.h" -#include <cctype> #include <utility> #include "cmOutputConverter.h" @@ -20,195 +19,194 @@ cmRulePlaceholderExpander::cmRulePlaceholderExpander( { } -std::string cmRulePlaceholderExpander::ExpandRuleVariable( - cmOutputConverter* outputConverter, std::string const& variable, - const RuleVariables& replaceValues) +std::string cmRulePlaceholderExpander::ExpandVariable( + std::string const& variable) { - if (replaceValues.LinkFlags) { + if (this->ReplaceValues->LinkFlags) { if (variable == "LINK_FLAGS") { - return replaceValues.LinkFlags; + return this->ReplaceValues->LinkFlags; } } - if (replaceValues.Manifests) { + if (this->ReplaceValues->Manifests) { if (variable == "MANIFESTS") { - return replaceValues.Manifests; + return this->ReplaceValues->Manifests; } } - if (replaceValues.Flags) { + if (this->ReplaceValues->Flags) { if (variable == "FLAGS") { - return replaceValues.Flags; + return this->ReplaceValues->Flags; } } - if (replaceValues.Source) { + if (this->ReplaceValues->Source) { if (variable == "SOURCE") { - return replaceValues.Source; + return this->ReplaceValues->Source; } } - if (replaceValues.DynDepFile) { + if (this->ReplaceValues->DynDepFile) { if (variable == "DYNDEP_FILE") { - return replaceValues.DynDepFile; + return this->ReplaceValues->DynDepFile; } } - if (replaceValues.PreprocessedSource) { + if (this->ReplaceValues->PreprocessedSource) { if (variable == "PREPROCESSED_SOURCE") { - return replaceValues.PreprocessedSource; + return this->ReplaceValues->PreprocessedSource; } } - if (replaceValues.AssemblySource) { + if (this->ReplaceValues->AssemblySource) { if (variable == "ASSEMBLY_SOURCE") { - return replaceValues.AssemblySource; + return this->ReplaceValues->AssemblySource; } } - if (replaceValues.Object) { + if (this->ReplaceValues->Object) { if (variable == "OBJECT") { - return replaceValues.Object; + return this->ReplaceValues->Object; } } - if (replaceValues.ObjectDir) { + if (this->ReplaceValues->ObjectDir) { if (variable == "OBJECT_DIR") { - return replaceValues.ObjectDir; + return this->ReplaceValues->ObjectDir; } } - if (replaceValues.ObjectFileDir) { + if (this->ReplaceValues->ObjectFileDir) { if (variable == "OBJECT_FILE_DIR") { - return replaceValues.ObjectFileDir; + return this->ReplaceValues->ObjectFileDir; } } - if (replaceValues.Objects) { + if (this->ReplaceValues->Objects) { if (variable == "OBJECTS") { - return replaceValues.Objects; + return this->ReplaceValues->Objects; } } - if (replaceValues.ObjectsQuoted) { + if (this->ReplaceValues->ObjectsQuoted) { if (variable == "OBJECTS_QUOTED") { - return replaceValues.ObjectsQuoted; + return this->ReplaceValues->ObjectsQuoted; } } - if (replaceValues.CudaCompileMode) { + if (this->ReplaceValues->CudaCompileMode) { if (variable == "CUDA_COMPILE_MODE") { - return replaceValues.CudaCompileMode; + return this->ReplaceValues->CudaCompileMode; } } - if (replaceValues.AIXExports) { + if (this->ReplaceValues->AIXExports) { if (variable == "AIX_EXPORTS") { - return replaceValues.AIXExports; + return this->ReplaceValues->AIXExports; } } - if (replaceValues.ISPCHeader) { + if (this->ReplaceValues->ISPCHeader) { if (variable == "ISPC_HEADER") { - return replaceValues.ISPCHeader; + return this->ReplaceValues->ISPCHeader; } } - if (replaceValues.Defines && variable == "DEFINES") { - return replaceValues.Defines; + if (this->ReplaceValues->Defines && variable == "DEFINES") { + return this->ReplaceValues->Defines; } - if (replaceValues.Includes && variable == "INCLUDES") { - return replaceValues.Includes; + if (this->ReplaceValues->Includes && variable == "INCLUDES") { + return this->ReplaceValues->Includes; } - if (replaceValues.SwiftLibraryName) { + if (this->ReplaceValues->SwiftLibraryName) { if (variable == "SWIFT_LIBRARY_NAME") { - return replaceValues.SwiftLibraryName; + return this->ReplaceValues->SwiftLibraryName; } } - if (replaceValues.SwiftModule) { + if (this->ReplaceValues->SwiftModule) { if (variable == "SWIFT_MODULE") { - return replaceValues.SwiftModule; + return this->ReplaceValues->SwiftModule; } } - if (replaceValues.SwiftModuleName) { + if (this->ReplaceValues->SwiftModuleName) { if (variable == "SWIFT_MODULE_NAME") { - return replaceValues.SwiftModuleName; + return this->ReplaceValues->SwiftModuleName; } } - if (replaceValues.SwiftOutputFileMap) { + if (this->ReplaceValues->SwiftOutputFileMap) { if (variable == "SWIFT_OUTPUT_FILE_MAP") { - return replaceValues.SwiftOutputFileMap; + return this->ReplaceValues->SwiftOutputFileMap; } } - if (replaceValues.SwiftSources) { + if (this->ReplaceValues->SwiftSources) { if (variable == "SWIFT_SOURCES") { - return replaceValues.SwiftSources; + return this->ReplaceValues->SwiftSources; } } - if (replaceValues.TargetPDB) { + if (this->ReplaceValues->TargetPDB) { if (variable == "TARGET_PDB") { - return replaceValues.TargetPDB; + return this->ReplaceValues->TargetPDB; } } - if (replaceValues.TargetCompilePDB) { + if (this->ReplaceValues->TargetCompilePDB) { if (variable == "TARGET_COMPILE_PDB") { - return replaceValues.TargetCompilePDB; + return this->ReplaceValues->TargetCompilePDB; } } - if (replaceValues.DependencyFile) { + if (this->ReplaceValues->DependencyFile) { if (variable == "DEP_FILE") { - return replaceValues.DependencyFile; + return this->ReplaceValues->DependencyFile; } } - if (replaceValues.DependencyTarget) { + if (this->ReplaceValues->DependencyTarget) { if (variable == "DEP_TARGET") { - return replaceValues.DependencyTarget; + return this->ReplaceValues->DependencyTarget; } } - if (replaceValues.Fatbinary) { + if (this->ReplaceValues->Fatbinary) { if (variable == "FATBINARY") { - return replaceValues.Fatbinary; + return this->ReplaceValues->Fatbinary; } } - if (replaceValues.RegisterFile) { + if (this->ReplaceValues->RegisterFile) { if (variable == "REGISTER_FILE") { - return replaceValues.RegisterFile; + return this->ReplaceValues->RegisterFile; } } - if (replaceValues.Target) { + if (this->ReplaceValues->Target) { if (variable == "TARGET_QUOTED") { - std::string targetQuoted = replaceValues.Target; + std::string targetQuoted = this->ReplaceValues->Target; if (!targetQuoted.empty() && targetQuoted.front() != '\"') { targetQuoted = '\"'; - targetQuoted += replaceValues.Target; + targetQuoted += this->ReplaceValues->Target; targetQuoted += '\"'; } return targetQuoted; } if (variable == "TARGET_UNQUOTED") { - std::string unquoted = replaceValues.Target; + std::string unquoted = this->ReplaceValues->Target; std::string::size_type sz = unquoted.size(); if (sz > 2 && unquoted.front() == '\"' && unquoted.back() == '\"') { unquoted = unquoted.substr(1, sz - 2); } return unquoted; } - if (replaceValues.LanguageCompileFlags) { + if (this->ReplaceValues->LanguageCompileFlags) { if (variable == "LANGUAGE_COMPILE_FLAGS") { - return replaceValues.LanguageCompileFlags; + return this->ReplaceValues->LanguageCompileFlags; } } - if (replaceValues.Target) { + if (this->ReplaceValues->Target) { if (variable == "TARGET") { - return replaceValues.Target; + return this->ReplaceValues->Target; } } if (variable == "TARGET_IMPLIB") { return this->TargetImpLib; } if (variable == "TARGET_VERSION_MAJOR") { - if (replaceValues.TargetVersionMajor) { - return replaceValues.TargetVersionMajor; + if (this->ReplaceValues->TargetVersionMajor) { + return this->ReplaceValues->TargetVersionMajor; } return "0"; } if (variable == "TARGET_VERSION_MINOR") { - if (replaceValues.TargetVersionMinor) { - return replaceValues.TargetVersionMinor; + if (this->ReplaceValues->TargetVersionMinor) { + return this->ReplaceValues->TargetVersionMinor; } return "0"; } - if (replaceValues.Target) { + if (this->ReplaceValues->Target) { if (variable == "TARGET_BASE") { // Strip the last extension off the target name. - std::string targetBase = replaceValues.Target; + std::string targetBase = this->ReplaceValues->Target; std::string::size_type pos = targetBase.rfind('.'); if (pos != std::string::npos) { return targetBase.substr(0, pos); @@ -220,54 +218,54 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( if (variable == "TARGET_SONAME" || variable == "SONAME_FLAG" || variable == "TARGET_INSTALLNAME_DIR") { // All these variables depend on TargetSOName - if (replaceValues.TargetSOName) { + if (this->ReplaceValues->TargetSOName) { if (variable == "TARGET_SONAME") { - return replaceValues.TargetSOName; + return this->ReplaceValues->TargetSOName; } - if (variable == "SONAME_FLAG" && replaceValues.SONameFlag) { - return replaceValues.SONameFlag; + if (variable == "SONAME_FLAG" && this->ReplaceValues->SONameFlag) { + return this->ReplaceValues->SONameFlag; } - if (replaceValues.TargetInstallNameDir && + if (this->ReplaceValues->TargetInstallNameDir && variable == "TARGET_INSTALLNAME_DIR") { - return replaceValues.TargetInstallNameDir; + return this->ReplaceValues->TargetInstallNameDir; } } return ""; } - if (replaceValues.LinkLibraries) { + if (this->ReplaceValues->LinkLibraries) { if (variable == "LINK_LIBRARIES") { - return replaceValues.LinkLibraries; + return this->ReplaceValues->LinkLibraries; } } - if (replaceValues.Language) { + if (this->ReplaceValues->Language) { if (variable == "LANGUAGE") { - return replaceValues.Language; + return this->ReplaceValues->Language; } } - if (replaceValues.CMTargetName) { + if (this->ReplaceValues->CMTargetName) { if (variable == "TARGET_NAME") { - return replaceValues.CMTargetName; + return this->ReplaceValues->CMTargetName; } } - if (replaceValues.CMTargetType) { + if (this->ReplaceValues->CMTargetType) { if (variable == "TARGET_TYPE") { - return replaceValues.CMTargetType; + return this->ReplaceValues->CMTargetType; } } - if (replaceValues.Output) { + if (this->ReplaceValues->Output) { if (variable == "OUTPUT") { - return replaceValues.Output; + return this->ReplaceValues->Output; } } if (variable == "CMAKE_COMMAND") { - return outputConverter->ConvertToOutputFormat( + return this->OutputConverter->ConvertToOutputFormat( cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL); } auto compIt = this->Compilers.find(variable); if (compIt != this->Compilers.end()) { - std::string ret = outputConverter->ConvertToOutputForExisting( + std::string ret = this->OutputConverter->ConvertToOutputForExisting( this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER"]); std::string const& compilerArg1 = this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER_ARG1"]; @@ -286,11 +284,12 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( this->VariableMappings["CMAKE_" + compIt->second + "_COMPILE_OPTIONS_SYSROOT"]; - if (compIt->second == replaceValues.Language && replaceValues.Launcher) { + if (compIt->second == this->ReplaceValues->Language && + this->ReplaceValues->Launcher) { // Add launcher as part of expansion so that it always appears // immediately before the command itself, regardless of whether the // overall rule template contains other content at the front. - ret = cmStrCat(replaceValues.Launcher, " ", ret); + ret = cmStrCat(this->ReplaceValues->Launcher, " ", ret); } // if there are required arguments to the compiler add it @@ -308,13 +307,14 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( !compilerOptionExternalToolchain.empty()) { ret += " "; ret += compilerOptionExternalToolchain; - ret += outputConverter->EscapeForShell(compilerExternalToolchain, true); + ret += + this->OutputConverter->EscapeForShell(compilerExternalToolchain, true); } std::string sysroot; // Some platforms may use separate sysroots for compiling and linking. // If we detect link flags, then we pass the link sysroot instead. // FIXME: Use a more robust way to detect link line expansion. - if (replaceValues.LinkFlags) { + if (this->ReplaceValues->LinkFlags) { sysroot = this->LinkerSysroot; } else { sysroot = this->CompilerSysroot; @@ -322,7 +322,7 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( if (!sysroot.empty() && !compilerOptionSysroot.empty()) { ret += " "; ret += compilerOptionSysroot; - ret += outputConverter->EscapeForShell(sysroot, true); + ret += this->OutputConverter->EscapeForShell(sysroot, true); } return ret; } @@ -331,13 +331,13 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( if (mapIt != this->VariableMappings.end()) { if (variable.find("_FLAG") == std::string::npos) { std::string ret = - outputConverter->ConvertToOutputForExisting(mapIt->second); + this->OutputConverter->ConvertToOutputForExisting(mapIt->second); - if (replaceValues.Launcher && variable == "CMAKE_LINKER") { + if (this->ReplaceValues->Launcher && variable == "CMAKE_LINKER") { // Add launcher as part of expansion so that it always appears // immediately before the command itself, regardless of whether the // overall rule template contains other content at the front. - ret = cmStrCat(replaceValues.Launcher, " ", ret); + ret = cmStrCat(this->ReplaceValues->Launcher, " ", ret); } return ret; @@ -351,47 +351,8 @@ void cmRulePlaceholderExpander::ExpandRuleVariables( cmOutputConverter* outputConverter, std::string& s, const RuleVariables& replaceValues) { - std::string::size_type start = s.find('<'); - // no variables to expand - if (start == std::string::npos) { - return; - } - std::string::size_type pos = 0; - std::string expandedInput; - while (start != std::string::npos && start < s.size() - 2) { - std::string::size_type end = s.find('>', start); - // if we find a < with no > we are done - if (end == std::string::npos) { - return; - } - char c = s[start + 1]; - // if the next char after the < is not A-Za-z then - // skip it and try to find the next < in the string - if (!isalpha(c)) { - start = s.find('<', start + 1); - } else { - // extract the var - std::string var = s.substr(start + 1, end - start - 1); - std::string replace = - this->ExpandRuleVariable(outputConverter, var, replaceValues); - expandedInput += s.substr(pos, start - pos); - - // Prevent consecutive whitespace in the output if the rule variable - // expands to an empty string. - bool consecutive = replace.empty() && start > 0 && s[start - 1] == ' ' && - end + 1 < s.size() && s[end + 1] == ' '; - if (consecutive) { - expandedInput.pop_back(); - } + this->OutputConverter = outputConverter; + this->ReplaceValues = &replaceValues; - expandedInput += replace; - - // move to next one - start = s.find('<', start + var.size() + 2); - pos = end + 1; - } - } - // add the rest of the input - expandedInput += s.substr(pos, s.size() - pos); - s = expandedInput; + this->ExpandVariables(s); } diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h index 852954f..23ec405 100644 --- a/Source/cmRulePlaceholderExpander.h +++ b/Source/cmRulePlaceholderExpander.h @@ -8,9 +8,11 @@ #include <map> #include <string> +#include "cmPlaceholderExpander.h" + class cmOutputConverter; -class cmRulePlaceholderExpander +class cmRulePlaceholderExpander : public cmPlaceholderExpander { public: cmRulePlaceholderExpander( @@ -76,16 +78,16 @@ public: std::string& string, const RuleVariables& replaceValues); - // Expand rule variables in a single string - std::string ExpandRuleVariable(cmOutputConverter* outputConverter, - std::string const& variable, - const RuleVariables& replaceValues); - private: + std::string ExpandVariable(std::string const& variable) override; + std::string TargetImpLib; std::map<std::string, std::string> Compilers; std::map<std::string, std::string> VariableMappings; std::string CompilerSysroot; std::string LinkerSysroot; + + cmOutputConverter* OutputConverter = nullptr; + RuleVariables const* ReplaceValues = nullptr; }; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 6059055..92a0ac4 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -1783,69 +1783,93 @@ void cmTarget::InsertPrecompileHeader(BT<std::string> const& entry) this->impl->PrecompileHeadersEntries.push_back(entry); } -static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop, - const std::string& value, - cmMakefile* context, - bool imported) +namespace { +void CheckLinkLibraryPattern(const std::string& property, + const std::string& value, cmMakefile* context) { - // Look for link-type keywords in the value. - static cmsys::RegularExpression keys("(^|;)(debug|optimized|general)(;|$)"); - if (!keys.find(value)) { + // Look for <LINK_LIBRARY:> and </LINK_LIBRARY:> internal tags + static cmsys::RegularExpression linkLibrary( + "(^|;)(</?LINK_LIBRARY:[^;>]*>)(;|$)"); + if (!linkLibrary.find(value)) { return; } + // Report an error. + context->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Property ", property, " contains the invalid item \"", + linkLibrary.match(2), "\". The ", property, + " property may contain the generator-expression " + "\"$<LINK_LIBRARY:...>\" " + "which may be used to specify how the libraries are linked.")); +} + +void CheckLINK_INTERFACE_LIBRARIES(const std::string& prop, + const std::string& value, + cmMakefile* context, bool imported) +{ // Support imported and non-imported versions of the property. const char* base = (imported ? "IMPORTED_LINK_INTERFACE_LIBRARIES" : "LINK_INTERFACE_LIBRARIES"); - // Report an error. - std::ostringstream e; - e << "Property " << prop << " may not contain link-type keyword \"" - << keys.match(2) << "\". " - << "The " << base << " property has a per-configuration " - << "version called " << base << "_<CONFIG> which may be " - << "used to specify per-configuration rules."; - if (!imported) { - e << " " - << "Alternatively, an IMPORTED library may be created, configured " - << "with a per-configuration location, and then named in the " - << "property value. " - << "See the add_library command's IMPORTED mode for details." - << "\n" - << "If you have a list of libraries that already contains the " - << "keyword, use the target_link_libraries command with its " - << "LINK_INTERFACE_LIBRARIES mode to set the property. " - << "The command automatically recognizes link-type keywords and sets " - << "the LINK_INTERFACE_LIBRARIES and LINK_INTERFACE_LIBRARIES_DEBUG " - << "properties accordingly."; - } - context->IssueMessage(MessageType::FATAL_ERROR, e.str()); -} - -static void cmTargetCheckINTERFACE_LINK_LIBRARIES(const std::string& value, - cmMakefile* context) -{ // Look for link-type keywords in the value. static cmsys::RegularExpression keys("(^|;)(debug|optimized|general)(;|$)"); - if (!keys.find(value)) { - return; + if (keys.find(value)) { + // Report an error. + std::ostringstream e; + e << "Property " << prop << " may not contain link-type keyword \"" + << keys.match(2) << "\". " + << "The " << base << " property has a per-configuration " + << "version called " << base << "_<CONFIG> which may be " + << "used to specify per-configuration rules."; + if (!imported) { + e << " " + << "Alternatively, an IMPORTED library may be created, configured " + << "with a per-configuration location, and then named in the " + << "property value. " + << "See the add_library command's IMPORTED mode for details." + << "\n" + << "If you have a list of libraries that already contains the " + << "keyword, use the target_link_libraries command with its " + << "LINK_INTERFACE_LIBRARIES mode to set the property. " + << "The command automatically recognizes link-type keywords and sets " + << "the LINK_INTERFACE_LIBRARIES and LINK_INTERFACE_LIBRARIES_DEBUG " + << "properties accordingly."; + } + context->IssueMessage(MessageType::FATAL_ERROR, e.str()); } - // Report an error. - std::ostringstream e; + CheckLinkLibraryPattern(base, value, context); +} + +void CheckLINK_LIBRARIES(const std::string& value, cmMakefile* context) +{ + CheckLinkLibraryPattern("LINK_LIBRARIES", value, context); +} - e << "Property INTERFACE_LINK_LIBRARIES may not contain link-type " - "keyword \"" - << keys.match(2) - << "\". The INTERFACE_LINK_LIBRARIES " - "property may contain configuration-sensitive generator-expressions " - "which may be used to specify per-configuration rules."; +void CheckINTERFACE_LINK_LIBRARIES(const std::string& value, + cmMakefile* context) +{ + // Look for link-type keywords in the value. + static cmsys::RegularExpression keys("(^|;)(debug|optimized|general)(;|$)"); + if (keys.find(value)) { + // Report an error. + std::ostringstream e; + + e << "Property INTERFACE_LINK_LIBRARIES may not contain link-type " + "keyword \"" + << keys.match(2) + << "\". The INTERFACE_LINK_LIBRARIES " + "property may contain configuration-sensitive generator-expressions " + "which may be used to specify per-configuration rules."; + + context->IssueMessage(MessageType::FATAL_ERROR, e.str()); + } - context->IssueMessage(MessageType::FATAL_ERROR, e.str()); + CheckLinkLibraryPattern("INTERFACE_LINK_LIBRARIES", value, context); } -static void cmTargetCheckIMPORTED_GLOBAL(const cmTarget* target, - cmMakefile* context) +void CheckIMPORTED_GLOBAL(const cmTarget* target, cmMakefile* context) { const auto& targets = context->GetOwnedImportedTargets(); auto it = @@ -1861,6 +1885,7 @@ static void cmTargetCheckIMPORTED_GLOBAL(const cmTarget* target, context->IssueMessage(MessageType::FATAL_ERROR, e.str()); } } +} void cmTarget::CheckProperty(const std::string& prop, cmMakefile* context) const @@ -1868,22 +1893,23 @@ void cmTarget::CheckProperty(const std::string& prop, // Certain properties need checking. if (cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES")) { if (cmValue value = this->GetProperty(prop)) { - cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, *value, context, false); + CheckLINK_INTERFACE_LIBRARIES(prop, *value, context, false); } - } - if (cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES")) { + } else if (cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES")) { if (cmValue value = this->GetProperty(prop)) { - cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, *value, context, true); + CheckLINK_INTERFACE_LIBRARIES(prop, *value, context, true); } - } - if (prop == "INTERFACE_LINK_LIBRARIES") { + } else if (prop == "LINK_LIBRARIES") { if (cmValue value = this->GetProperty(prop)) { - cmTargetCheckINTERFACE_LINK_LIBRARIES(*value, context); + CheckLINK_LIBRARIES(*value, context); } - } - if (prop == "IMPORTED_GLOBAL") { + } else if (prop == "INTERFACE_LINK_LIBRARIES") { + if (cmValue value = this->GetProperty(prop)) { + CheckINTERFACE_LINK_LIBRARIES(*value, context); + } + } else if (prop == "IMPORTED_GLOBAL") { if (this->IsImported()) { - cmTargetCheckIMPORTED_GLOBAL(this, context); + CheckIMPORTED_GLOBAL(this, context); } } } diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index 94fcdd9..0ba93fb 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -354,6 +354,9 @@ bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args, target->SetProperty("LINK_INTERFACE_LIBRARIES", ""); } + target->CheckProperty("LINK_LIBRARIES", &mf); + target->CheckProperty("INTERFACE_LINK_LIBRARIES", &mf); + return true; } diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx index fd5402c..24394d9 100644 --- a/Source/cmVariableWatchCommand.cxx +++ b/Source/cmVariableWatchCommand.cxx @@ -58,7 +58,7 @@ void cmVariableWatchCommandVariableAccessed(const std::string& variable, { stack, cmListFileArgument::Quoted, fakeLineNo } }; - cmListFileFunction newLFF{ data->Command, fakeLineNo, + cmListFileFunction newLFF{ data->Command, fakeLineNo, fakeLineNo, std::move(newLFFArgs) }; cmExecutionStatus status(*makefile); if (!makefile->ExecuteCommand(newLFF, status)) { diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 8ffb664..be1b0de 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -50,6 +50,40 @@ #include "cmValue.h" #include "cmVisualStudioGeneratorOptions.h" +namespace { +std::string getProjectFileExtension(VsProjectType projectType) +{ + switch (projectType) { + case VsProjectType::csproj: + return ".csproj"; + case VsProjectType::proj: + return ".proj"; + case VsProjectType::vcxproj: + return ".vcxproj"; + // Valid inputs shouldn't reach here. This default is needed so that all + // paths return value (C4715). + default: + return ""; + } +} + +VsProjectType computeProjectType(cmGeneratorTarget const* t) +{ + if (t->GetName() == CMAKE_CHECK_BUILD_SYSTEM_TARGET) { + return VsProjectType::proj; + } + if (t->IsCSharpOnly()) { + return VsProjectType::csproj; + } + return VsProjectType::vcxproj; +} + +std::string computeProjectFileExtension(cmGeneratorTarget const* t) +{ + return getProjectFileExtension(computeProjectType(t)); +} +} + struct cmIDEFlagTable; static void ConvertToWindowsSlash(std::string& s); @@ -235,29 +269,6 @@ static bool cmVS10IsTargetsFile(std::string const& path) return cmSystemTools::Strucmp(ext.c_str(), ".targets") == 0; } -static VsProjectType computeProjectType(cmGeneratorTarget const* t) -{ - if (t->IsCSharpOnly()) { - return VsProjectType::csproj; - } - return VsProjectType::vcxproj; -} - -static std::string computeProjectFileExtension(VsProjectType projectType) -{ - switch (projectType) { - case VsProjectType::csproj: - return ".csproj"; - default: - return ".vcxproj"; - } -} - -static std::string computeProjectFileExtension(cmGeneratorTarget const* t) -{ - return computeProjectFileExtension(computeProjectType(t)); -} - cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator( cmGeneratorTarget* target, cmGlobalVisualStudio10Generator* gg) : GeneratorTarget(target) @@ -355,7 +366,7 @@ void cmVisualStudio10TargetGenerator::Generate() this->ProjectType = computeProjectType(this->GeneratorTarget); this->Managed = this->ProjectType == VsProjectType::csproj; const std::string ProjectFileExtension = - computeProjectFileExtension(this->ProjectType); + getProjectFileExtension(this->ProjectType); if (this->ProjectType == VsProjectType::csproj && this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) { @@ -416,10 +427,12 @@ void cmVisualStudio10TargetGenerator::Generate() char magic[] = { char(0xEF), char(0xBB), char(0xBF) }; BuildFileStream.write(magic, 3); - if (this->ProjectType == VsProjectType::csproj && - this->GeneratorTarget->IsDotNetSdkTarget() && - this->GlobalGenerator->GetVersion() >= - cmGlobalVisualStudioGenerator::VSVersion::VS16) { + if (this->ProjectType == VsProjectType::proj) { + this->WriteZeroCheckProj(BuildFileStream); + } else if (this->ProjectType == VsProjectType::csproj && + this->GeneratorTarget->IsDotNetSdkTarget() && + this->GlobalGenerator->GetVersion() >= + cmGlobalVisualStudioGenerator::VSVersion::VS16) { this->WriteSdkStyleProjectFile(BuildFileStream); } else { this->WriteClassicMsBuildProjectFile(BuildFileStream); @@ -681,6 +694,8 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile( .Attribute("Project", VS10_CSharp_DEFAULT_PROPS) .Attribute("Condition", "Exists('" VS10_CSharp_DEFAULT_PROPS "')"); break; + default: + break; } this->WriteProjectConfigurationValues(e0); @@ -737,6 +752,8 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile( case VsProjectType::csproj: props = VS10_CSharp_USER_PROPS; break; + default: + break; } if (cmValue p = this->GeneratorTarget->GetProperty("VS_USER_PROPS")) { props = *p; @@ -779,6 +796,8 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile( Elem(e0, "Import").Attribute("Project", VS10_CSharp_TARGETS); } break; + default: + break; } this->WriteTargetSpecificReferences(e0); @@ -944,6 +963,45 @@ void cmVisualStudio10TargetGenerator::WriteSdkStyleProjectFile( this->WriteProjectReferences(e0); } +void cmVisualStudio10TargetGenerator::WriteZeroCheckProj( + cmGeneratedFileStream& BuildFileStream) +{ + // ZERO_CHECK.proj is an XML file without any imports or targets. This is a + // ProjectReference for other targets and therefore, it needs to follow the + // ProjectReference protocol as documented here: + // https://github.com/dotnet/msbuild/blob/main/documentation/ProjectReference-Protocol.md + // + // We implement MSBuild target Build from WriteCustomCommand which calls + // WriteZeroCheckBuildTarget after setting up the command generator. MSBuild + // target Clean is a no-op as we do all the work for ZERO_CHECK on Build. + // MSBuild target GetTargetPath is needed and is no-op. + // MSBuild targets GetNativeManifest and GetCopyToOutputDirectoryItems are + // needed for MSBuild versions below 15.7 and are no-op. MSBuild target + // BeforeBuild is needed for supporting GLOBs. + BuildFileStream << "<?xml version=\"1.0\" encoding=\"" + << this->GlobalGenerator->Encoding() << "\"?>"; + { + Elem e0(BuildFileStream, "Project"); + e0.Attribute("DefaultTargets", "Build"); + e0.Attribute("ToolsVersion", this->GlobalGenerator->GetToolsVersion()); + e0.Attribute("xmlns", + "http://schemas.microsoft.com/developer/msbuild/2003"); + + this->WriteCustomCommands(e0); + + for (const char* targetName : + { "Clean", "GetTargetPath", "GetNativeManifest", + "GetCopyToOutputDirectoryItems" }) { + { + Elem e1(e0, "Target"); + e1.Attribute("Name", targetName); + } + } + + this->WriteZeroCheckBeforeBuildTarget(e0); + } +} + void cmVisualStudio10TargetGenerator::WriteCommonPropertyGroupGlobals(Elem& e1) { e1.Attribute("Label", "Globals"); @@ -1659,11 +1717,16 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( } } } + if (this->ProjectType == VsProjectType::proj) { + this->WriteZeroCheckBuildTarget(e0, command, source); + return; + } + cmLocalVisualStudio7Generator* lg = this->LocalGenerator; std::unique_ptr<Elem> spe1; std::unique_ptr<Elem> spe2; - if (this->ProjectType != VsProjectType::csproj) { + if (this->ProjectType == VsProjectType::vcxproj) { spe1 = cm::make_unique<Elem>(e0, "ItemGroup"); spe2 = cm::make_unique<Elem>(*spe1, "CustomBuild"); this->WriteSource(*spe2, source); @@ -3016,6 +3079,134 @@ void cmVisualStudio10TargetGenerator::OutputLinkIncremental( } } +void cmVisualStudio10TargetGenerator::WriteZeroCheckBuildTarget( + cmVisualStudio10TargetGenerator::Elem& e0, const cmCustomCommand& command, + const cmSourceFile* source) +{ + cmLocalVisualStudio7Generator* lg = this->LocalGenerator; + + Elem e1(e0, "Target"); + e1.Attribute("Name", "Build"); + + std::string noConfig{}; + cmCustomCommandGenerator ccg{ command, noConfig, lg, true }; + std::string comment = lg->ConstructComment(ccg); + comment = cmVS10EscapeComment(comment); + std::string script = lg->ConstructScript(ccg); + bool symbolic = false; + // input files for custom command + std::stringstream additional_inputs; + { + const char* sep = ""; + if (this->ProjectType == VsProjectType::proj) { + // List explicitly the path to primary input. + std::string sourceFullPath = source->GetFullPath(); + ConvertToWindowsSlash(sourceFullPath); + additional_inputs << sourceFullPath; + sep = ";"; + } + + // Avoid listing an input more than once. + std::set<std::string> unique_inputs; + // The source is either implicitly an input or has been added above. + unique_inputs.insert(source->GetFullPath()); + + for (std::string const& d : ccg.GetDepends()) { + std::string dep; + if (lg->GetRealDependency(d, noConfig, dep)) { + if (!unique_inputs.insert(dep).second) { + // already listed + continue; + } + ConvertToWindowsSlash(dep); + additional_inputs << sep << dep; + sep = ";"; + if (!symbolic) { + if (cmSourceFile* sf = this->Makefile->GetSource( + dep, cmSourceFileLocationKind::Known)) { + symbolic = sf->GetPropertyAsBool("SYMBOLIC"); + } + } + } + } + } + // output files for custom command + std::stringstream outputs; + { + const char* sep = ""; + for (std::string const& o : ccg.GetOutputs()) { + std::string out = o; + ConvertToWindowsSlash(out); + outputs << sep << out; + sep = ";"; + if (!symbolic) { + if (cmSourceFile* sf = + this->Makefile->GetSource(o, cmSourceFileLocationKind::Known)) { + symbolic = sf->GetPropertyAsBool("SYMBOLIC"); + } + } + } + } + script += lg->FinishConstructScript(this->ProjectType); + + e1.Attribute("Inputs", cmVS10EscapeAttr(additional_inputs.str())); + e1.Attribute("Outputs", cmVS10EscapeAttr(outputs.str())); + + e1.SetHasElements(); + + if (!comment.empty()) { + Elem(e1, "Message").Attribute("Text", comment); + } + Elem(e1, "Exec").Attribute("Command", script); +} + +void cmVisualStudio10TargetGenerator::WriteZeroCheckBeforeBuildTarget( + cmVisualStudio10TargetGenerator::Elem& e0) +{ + const auto& commands = this->GeneratorTarget->GetPreBuildCommands(); + if (commands.empty()) { + return; + } + + { + Elem e1(e0, "Target"); + e1.Attribute("Name", "BeforeBuild"); + e1.Attribute("BeforeTargets", "Build"); + + cmLocalVisualStudio7Generator* lg = this->LocalGenerator; + std::string script; + const char* pre = ""; + std::string comment; + for (cmCustomCommand const& cc : commands) { + cmCustomCommandGenerator ccg(cc, std::string{}, lg); + if (!ccg.HasOnlyEmptyCommandLines()) { + comment += pre; + comment += lg->ConstructComment(ccg); + script += pre; + pre = "\n"; + script += lg->ConstructScript(ccg); + } + } + + if (script.empty()) { + return; + } + + script += lg->FinishConstructScript(this->ProjectType); + comment = cmVS10EscapeComment(comment); + std::string strippedComment = comment; + strippedComment.erase( + std::remove(strippedComment.begin(), strippedComment.end(), '\t'), + strippedComment.end()); + + e1.SetHasElements(); + if (!comment.empty() && !strippedComment.empty()) { + Elem(e1, "Message").Attribute("Text", comment); + } + Elem(e1, "Exec").Attribute("Command", script); + } +} + std::vector<std::string> cmVisualStudio10TargetGenerator::GetIncludes( std::string const& config, std::string const& lang) const { @@ -3057,6 +3248,8 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( cm::make_unique<Options>(this->LocalGenerator, Options::CSharpCompiler, gg->GetCSharpFlagTable()); break; + default: + break; } Options& clOptions = *pOptions; @@ -3182,6 +3375,8 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( return def.find('=') != std::string::npos; }); break; + default: + break; } clOptions.AddDefines(targetDefines); @@ -3309,7 +3504,9 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( } else if (this->MSTools) { cmsys::RegularExpression clangToolset("v[0-9]+_clang_.*"); const char* toolset = this->GlobalGenerator->GetPlatformToolset(); - if (toolset && clangToolset.find(toolset)) { + cmValue noCompileBatching = + this->GeneratorTarget->GetProperty("VS_NO_COMPILE_BATCHING"); + if (noCompileBatching.IsOn() || (toolset && clangToolset.find(toolset))) { e2.Element("ObjectFileName", "$(IntDir)%(filename).obj"); } else { e2.Element("ObjectFileName", "$(IntDir)"); @@ -3688,7 +3885,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions( this->LocalGenerator->MaybeRelativeToCurBinDir(l.Value.Value); ConvertToWindowsSlash(path); if (!cmVS10IsTargetsFile(l.Value.Value)) { - libVec.push_back(path); + libVec.push_back(l.HasFeature() ? l.GetFormattedItem(path).Value + : path); } } else { libVec.push_back(l.Value.Value); @@ -4305,6 +4503,9 @@ void cmVisualStudio10TargetGenerator::AddLibraries( this->AdditionalUsingDirectories[config].insert( cmSystemTools::GetFilenamePath(location)); break; + default: + // In .proj files, we wouldn't be referencing libraries. + break; } } } @@ -4326,7 +4527,8 @@ void cmVisualStudio10TargetGenerator::AddLibraries( if (cmVS10IsTargetsFile(l.Value.Value)) { vsTargetVec.push_back(path); } else { - libVec.push_back(path); + libVec.push_back(l.HasFeature() ? l.GetFormattedItem(path).Value + : path); } } else if (!l.Target || l.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 8d777a3..5e74779 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -264,6 +264,13 @@ private: void WriteClassicMsBuildProjectFile(cmGeneratedFileStream& BuildFileStream); void WriteSdkStyleProjectFile(cmGeneratedFileStream& BuildFileStream); + void WriteZeroCheckProj(cmGeneratedFileStream& BuildFileStream); + void WriteZeroCheckBuildTarget(cmVisualStudio10TargetGenerator::Elem& e0, + const cmCustomCommand& command, + const cmSourceFile* source); + void WriteZeroCheckBeforeBuildTarget( + cmVisualStudio10TargetGenerator::Elem& e0); + void WriteCommonPropertyGroupGlobals( cmVisualStudio10TargetGenerator::Elem& e1); diff --git a/Source/cmVsProjectType.h b/Source/cmVsProjectType.h index 8899267..04053a0 100644 --- a/Source/cmVsProjectType.h +++ b/Source/cmVsProjectType.h @@ -7,5 +7,6 @@ enum class VsProjectType { vcxproj, - csproj + csproj, + proj, }; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index d80c4bc..07732e5 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -1454,7 +1454,7 @@ void cmake::PrintTraceFormatVersion() Json::StreamWriterBuilder builder; builder["indentation"] = ""; version["major"] = 1; - version["minor"] = 1; + version["minor"] = 2; val["version"] = version; msg = Json::writeString(builder, val); #endif diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 32c01e5..ba61a83 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -97,7 +97,8 @@ void CMakeCommandUsage(std::string const& program) << "Available commands: \n" << " capabilities - Report capabilities built into cmake " "in JSON format\n" - << " cat <files>... - concat the files and print them to the standard output\n" + << " cat [--] <files>... - concat the files and print them to the " + "standard output\n" << " chdir dir cmd [args...] - run command in a given directory\n" << " compare_files [--ignore-eol] file1 file2\n" << " - check if file1 is same as file2\n" @@ -110,7 +111,7 @@ void CMakeCommandUsage(std::string const& program) << " echo [<string>...] - displays arguments as text\n" << " echo_append [<string>...] - displays arguments as text but no new " "line\n" - << " env [--unset=NAME]... [NAME=VALUE]... COMMAND [ARG]...\n" + << " env [--unset=NAME ...] [NAME=VALUE ...] [--] <command> [<arg>...]\n" << " - run command in a modified environment\n" << " environment - display the current environment\n" << " make_directory <dir>... - create parent and <dir> directories\n" @@ -125,8 +126,9 @@ void CMakeCommandUsage(std::string const& program) << " remove_directory <dir>... - remove directories and their contents (deprecated: use rm instead)\n" << " rename oldname newname - rename a file or directory " "(on one volume)\n" - << " rm [-rRf] <file/dir>... - remove files or directories, use -f to " - "force it, r or R to remove directories and their contents recursively\n" + << " rm [-rRf] [--] <file/dir>... - remove files or directories, use -f " + "to force it, r or R to remove directories and their contents " + "recursively\n" << " sleep <number>... - sleep for given number of seconds\n" << " tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n" << " - create or extract a tar or zip archive\n" @@ -793,6 +795,12 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, auto ae = args.cend(); for (; ai != ae; ++ai) { std::string const& a = *ai; + if (a == "--") { + // Stop parsing options/environment variables; the next argument + // should be the command. + ++ai; + break; + } if (cmHasLiteralPrefix(a, "--unset=")) { // Unset environment variable. cmSystemTools::UnPutEnv(a.substr(8)); @@ -1051,9 +1059,12 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, // Command to concat files into one if (args[1] == "cat" && args.size() >= 3) { int return_value = 0; + bool doing_options = true; for (auto const& arg : cmMakeRange(args).advance(2)) { - if (cmHasLiteralPrefix(arg, "-")) { - if (arg != "--") { + if (doing_options && cmHasLiteralPrefix(arg, "-")) { + if (arg == "--") { + doing_options = false; + } else { cmSystemTools::Error(arg + ": option not handled"); return_value = 1; } diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 6946ffb..8ebe5ed 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -294,26 +294,6 @@ if(BUILD_TESTING) mark_as_advanced(CTEST_TEST_CTEST) endif () - # Should tests that use CVS be run? - # - set(do_cvs_tests 0) - - if(EXISTS ${CMAKE_ROOT}/Modules/FindCVS.cmake) - find_package(CVS QUIET) - else() - find_program(CVS_EXECUTABLE NAMES cvs) - endif() - - if(CVS_EXECUTABLE) - set(do_cvs_tests 1) - endif() - - if(do_cvs_tests AND NOT UNIX) - if("${CVS_EXECUTABLE}" MATCHES "cygwin") - set(do_cvs_tests 0) - endif() - endif() - # Should CPack tests be run? By default, yes, but... # # Disable packaging test on Apple 10.3 and below. PackageMaker starts @@ -1574,6 +1554,12 @@ if(BUILD_TESTING) ADD_TEST_MACRO(FindMatlab.targets_checks ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>) endif() + set(ExternalProject_BUILD_OPTIONS "") + foreach(vcs CVS SVN GIT HG) + if(DEFINED CMake_TEST_ExternalProject_${vcs}) + list(APPEND ExternalProject_BUILD_OPTIONS -DEP_TEST_${vcs}=${CMake_TEST_ExternalProject_${vcs}}) + endif() + endforeach() add_test(ExternalProject ${CMAKE_CTEST_COMMAND} --build-and-test "${CMake_SOURCE_DIR}/Tests/ExternalProject" @@ -1582,6 +1568,7 @@ if(BUILD_TESTING) --build-project ExternalProjectTest --build-exe-dir "${CMake_BINARY_DIR}/Tests/ExternalProject" --force-new-ctest-process + --build-options ${ExternalProject_BUILD_OPTIONS} --test-command ${CMAKE_CTEST_COMMAND} -V ) list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProject") @@ -2562,27 +2549,8 @@ if(BUILD_TESTING) # -S "${CMake_BINARY_DIR}/Tests/CTestScriptMode/CTestTestScriptMode.cmake" # ) - # A test for ctest_build() with targets in subdirectories - set(ctest_configure_options) - if(CMAKE_GENERATOR_PLATFORM) - list(APPEND ctest_configure_options -A ${CMAKE_GENERATOR_PLATFORM}) - endif() - if(CMAKE_GENERATOR_TOOLSET) - list(APPEND ctest_configure_options -T ${CMAKE_GENERATOR_TOOLSET}) - endif() - if(CMake_TEST_EXPLICIT_MAKE_PROGRAM) - list(APPEND ctest_configure_options -DCMAKE_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM}) - endif() - configure_file("${CMake_SOURCE_DIR}/Tests/CTestBuildCommandProjectInSubdir/CTestBuildCommandProjectInSubdir.cmake.in" - "${CMake_BINARY_DIR}/Tests/CTestBuildCommandProjectInSubdir/CTestBuildCommandProjectInSubdir.cmake" @ONLY) - unset(ctest_configure_options) - add_test(CTest.BuildCommand.ProjectInSubdir - ${CMAKE_CTEST_COMMAND} -S "${CMake_BINARY_DIR}/Tests/CTestBuildCommandProjectInSubdir/CTestBuildCommandProjectInSubdir.cmake") - list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CTestBuildCommandProjectInSubdir/Nested") - - set(CTEST_TEST_UPDATE 1) - if(CTEST_TEST_UPDATE) - # Test CTest Update with Subversion + # Test CTest Update with Subversion + if(NOT DEFINED CMake_TEST_CTestUpdate_SVN OR CMake_TEST_CTestUpdate_SVN) find_package(Subversion QUIET) if(Subversion_FOUND) get_filename_component(_Subversion_BIN_DIR @@ -2595,129 +2563,134 @@ if(BUILD_TESTING) set(Subversion_FOUND FALSE) endif() endif() - if(Subversion_FOUND) - set(CTestUpdateSVN_DIR "CTest UpdateSVN") - configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateSVN.cmake.in" - "${CMake_BINARY_DIR}/Tests/CTestUpdateSVN.cmake" @ONLY) - add_test(CTest.UpdateSVN ${CMAKE_CMAKE_COMMAND} - -P "${CMake_BINARY_DIR}/Tests/CTestUpdateSVN.cmake" - ) - list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateSVN_DIR}") + endif() + if(NOT DEFINED CMake_TEST_CTestUpdate_SVN AND Subversion_FOUND) + set(CMake_TEST_CTestUpdate_SVN 1) + endif() + if(CMake_TEST_CTestUpdate_SVN) + if(NOT Subversion_FOUND) + message(FATAL_ERROR "CMake_TEST_CTestUpdate_SVN enabled but Subversion is not found.") endif() + set(CTestUpdateSVN_DIR "CTest UpdateSVN") + configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateSVN.cmake.in" + "${CMake_BINARY_DIR}/Tests/CTestUpdateSVN.cmake" @ONLY) + add_test(CTest.UpdateSVN ${CMAKE_CMAKE_COMMAND} + -P "${CMake_BINARY_DIR}/Tests/CTestUpdateSVN.cmake" + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateSVN_DIR}") + endif() - # Test CTest Update with CVS - if(EXISTS ${CMAKE_ROOT}/Modules/FindCVS.cmake) - find_package(CVS QUIET) - else() - find_program(CVS_EXECUTABLE NAMES cvs) - set(CVS_FOUND ${CVS_EXECUTABLE}) - endif() - set(CTEST_TEST_UPDATE_CVS ${CVS_FOUND}) - if(CTEST_TEST_UPDATE_CVS AND NOT UNIX) - if("${CVS_EXECUTABLE}" MATCHES "cygwin") - message(STATUS "No CTest.UpdateCVS test with cygwin cvs.exe outside cygwin!") - set(CTEST_TEST_UPDATE_CVS 0) - endif() - endif() - if(CTEST_TEST_UPDATE_CVS) - set(CTestUpdateCVS_DIR "CTest UpdateCVS") - configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateCVS.cmake.in" - "${CMake_BINARY_DIR}/Tests/CTestUpdateCVS.cmake" @ONLY) - add_test(CTest.UpdateCVS ${CMAKE_CMAKE_COMMAND} - -P "${CMake_BINARY_DIR}/Tests/CTestUpdateCVS.cmake" - ) - list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateCVS_DIR}") + # Test CTest Update with CVS + if(NOT DEFINED CMake_TEST_CTestUpdate_CVS OR CMake_TEST_CTestUpdate_CVS) + find_program(CVS_EXECUTABLE NAMES cvs) + mark_as_advanced(CVS_EXECUTABLE) + endif() + if(NOT DEFINED CMake_TEST_CTestUpdate_CVS AND CVS_EXECUTABLE + AND (UNIX OR NOT "${CVS_EXECUTABLE}" MATCHES "cygwin")) + set(CMake_TEST_CTestUpdate_CVS 1) + endif() + if(CMake_TEST_CTestUpdate_CVS) + if(NOT CVS_EXECUTABLE) + message(FATAL_ERROR "CMake_TEST_CTestUpdate_CVS enabled but CVS_EXECUTABLE is not found.") endif() + set(CTestUpdateCVS_DIR "CTest UpdateCVS") + configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateCVS.cmake.in" + "${CMake_BINARY_DIR}/Tests/CTestUpdateCVS.cmake" @ONLY) + add_test(CTest.UpdateCVS ${CMAKE_CMAKE_COMMAND} + -P "${CMake_BINARY_DIR}/Tests/CTestUpdateCVS.cmake" + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateCVS_DIR}") + endif() - # Test CTest Update with BZR + # Test CTest Update with BZR + if(CMake_TEST_CTestUpdate_BZR) find_program(BZR_EXECUTABLE NAMES bzr) mark_as_advanced(BZR_EXECUTABLE) - set(CTEST_TEST_UPDATE_BZR 0) - if(BZR_EXECUTABLE) - if(NOT "${BZR_EXECUTABLE}" MATCHES "cygwin" OR UNIX) - set(CTEST_TEST_UPDATE_BZR 1) - endif() - endif() - if(CTEST_TEST_UPDATE_BZR) - # Check if xmloutput plugin is there - execute_process(COMMAND ${BZR_EXECUTABLE} xmlplugins RESULT_VARIABLE xmlplugres - OUTPUT_QUIET ERROR_QUIET) - if( NOT ${xmlplugres} ) - set(CTestUpdateBZR_DIR "CTest UpdateBZR") - configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateBZR.cmake.in" - "${CMake_BINARY_DIR}/Tests/CTestUpdateBZR.cmake" @ONLY) - add_test(CTest.UpdateBZR ${CMAKE_CMAKE_COMMAND} - -P "${CMake_BINARY_DIR}/Tests/CTestUpdateBZR.cmake" - ) - list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateBZR_DIR}") - set(CTestUpdateBZR_DIR "CTest UpdateBZR_CLocale") - configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateBZR.cmake.in" - "${CMake_BINARY_DIR}/Tests/CTestUpdateBZR_CLocale.cmake" @ONLY) - add_test(CTest.UpdateBZR.CLocale ${CMAKE_CMAKE_COMMAND} - -P "${CMake_BINARY_DIR}/Tests/CTestUpdateBZR_CLocale.cmake" - ) - set_tests_properties(CTest.UpdateBZR.CLocale PROPERTIES ENVIRONMENT LC_ALL=C) - list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateBZR_DIR}") - endif() - endif() + if(NOT BZR_EXECUTABLE) + message(FATAL_ERROR "CMake_TEST_CTestUpdate_BZR enabled but BZR_EXECUTABLE is not found.") + endif() + set(CTestUpdateBZR_DIR "CTest UpdateBZR") + configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateBZR.cmake.in" + "${CMake_BINARY_DIR}/Tests/CTestUpdateBZR.cmake" @ONLY) + add_test(CTest.UpdateBZR ${CMAKE_CMAKE_COMMAND} + -P "${CMake_BINARY_DIR}/Tests/CTestUpdateBZR.cmake" + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateBZR_DIR}") + set(CTestUpdateBZR_DIR "CTest UpdateBZR_CLocale") + configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateBZR.cmake.in" + "${CMake_BINARY_DIR}/Tests/CTestUpdateBZR_CLocale.cmake" @ONLY) + add_test(CTest.UpdateBZR.CLocale ${CMAKE_CMAKE_COMMAND} + -P "${CMake_BINARY_DIR}/Tests/CTestUpdateBZR_CLocale.cmake" + ) + set_tests_properties(CTest.UpdateBZR.CLocale PROPERTIES ENVIRONMENT LC_ALL=C) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateBZR_DIR}") + endif() - # Test CTest Update with GIT + # Test CTest Update with GIT + if(NOT DEFINED CMake_TEST_CTestUpdate_GIT OR CMake_TEST_CTestUpdate_GIT) find_program(GIT_EXECUTABLE NAMES git) mark_as_advanced(GIT_EXECUTABLE) - set(CTEST_TEST_UPDATE_GIT 0) - if(GIT_EXECUTABLE) - if(NOT "${GIT_EXECUTABLE}" MATCHES "cygwin" OR UNIX) - set(CTEST_TEST_UPDATE_GIT 1) - endif() - endif() - if(CTEST_TEST_UPDATE_GIT) - set(CTestUpdateGIT_DIR "CTest UpdateGIT") - configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateGIT.cmake.in" - "${CMake_BINARY_DIR}/Tests/CTestUpdateGIT.cmake" @ONLY) - add_test(CTest.UpdateGIT ${CMAKE_CMAKE_COMMAND} - -P "${CMake_BINARY_DIR}/Tests/CTestUpdateGIT.cmake" - ) - list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateGIT_DIR}") + endif() + if(NOT DEFINED CMake_TEST_CTestUpdate_GIT AND GIT_EXECUTABLE + AND (UNIX OR NOT "${GIT_EXECUTABLE}" MATCHES "cygwin")) + set(CMake_TEST_CTestUpdate_GIT 1) + endif() + if(CMake_TEST_CTestUpdate_GIT) + if(NOT GIT_EXECUTABLE) + message(FATAL_ERROR "CMake_TEST_CTestUpdate_GIT enabled but GIT_EXECUTABLE is not found.") endif() + set(CTestUpdateGIT_DIR "CTest UpdateGIT") + configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateGIT.cmake.in" + "${CMake_BINARY_DIR}/Tests/CTestUpdateGIT.cmake" @ONLY) + add_test(CTest.UpdateGIT ${CMAKE_CMAKE_COMMAND} + -P "${CMake_BINARY_DIR}/Tests/CTestUpdateGIT.cmake" + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateGIT_DIR}") + endif() - # Test CTest Update with HG + # Test CTest Update with HG + if(NOT DEFINED CMake_TEST_CTestUpdate_HG OR CMake_TEST_CTestUpdate_HG) find_program(HG_EXECUTABLE NAMES hg) mark_as_advanced(HG_EXECUTABLE) - set(CTEST_TEST_UPDATE_HG 0) - if(HG_EXECUTABLE) - if(NOT "${HG_EXECUTABLE}" MATCHES "cygwin" OR UNIX) - set(CTEST_TEST_UPDATE_HG 1) - endif() - endif() - if(CTEST_TEST_UPDATE_HG) - set(CTestUpdateHG_DIR "CTest UpdateHG") - configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateHG.cmake.in" - "${CMake_BINARY_DIR}/Tests/CTestUpdateHG.cmake" @ONLY) - add_test(CTest.UpdateHG ${CMAKE_CMAKE_COMMAND} - -P "${CMake_BINARY_DIR}/Tests/CTestUpdateHG.cmake" - ) - list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateHG_DIR}") + endif() + if(NOT DEFINED CMake_TEST_CTestUpdate_HG AND HG_EXECUTABLE + AND (UNIX OR NOT "${HG_EXECUTABLE}" MATCHES "cygwin")) + set(CMake_TEST_CTestUpdate_HG 1) + endif() + if(CMake_TEST_CTestUpdate_HG) + if(NOT HG_EXECUTABLE) + message(FATAL_ERROR "CMake_TEST_CTestUpdate_HG enabled but HG_EXECUTABLE is not found.") endif() + set(CTestUpdateHG_DIR "CTest UpdateHG") + configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateHG.cmake.in" + "${CMake_BINARY_DIR}/Tests/CTestUpdateHG.cmake" @ONLY) + add_test(CTest.UpdateHG ${CMAKE_CMAKE_COMMAND} + -P "${CMake_BINARY_DIR}/Tests/CTestUpdateHG.cmake" + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateHG_DIR}") + endif() - # Test CTest Update with P4 + # Test CTest Update with P4 + if(NOT DEFINED CMake_TEST_CTestUpdate_P4 OR CMake_TEST_CTestUpdate_P4) find_program(P4_EXECUTABLE NAMES p4) find_program(P4D_EXECUTABLE NAMES p4d) mark_as_advanced(P4_EXECUTABLE P4D_EXECUTABLE) - set(CTEST_TEST_UPDATE_P4 0) - if(P4_EXECUTABLE AND P4D_EXECUTABLE) - if(NOT "${P4_EXECUTABLE};${P4D_EXECUTABLE}" MATCHES "cygwin" OR UNIX) - set(CTEST_TEST_UPDATE_P4 1) - endif() - endif() - if(CTEST_TEST_UPDATE_P4) - set(CTestUpdateP4_DIR "CTest UpdateP4") - configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateP4.cmake.in" - "${CMake_BINARY_DIR}/Tests/CTestUpdateP4.cmake" @ONLY) - add_test(CTest.UpdateP4 ${CMAKE_CMAKE_COMMAND} - -P "${CMake_BINARY_DIR}/Tests/CTestUpdateP4.cmake" - ) - list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateP4_DIR}") + endif() + if(NOT DEFINED CMake_TEST_CTestUpdate_P4 AND P4_EXECUTABLE AND P4D_EXECUTABLE + AND (UNIX OR NOT "${P4_EXECUTABLE};${P4D_EXECUTABLE}" MATCHES "cygwin")) + set(CMake_TEST_CTestUpdate_P4 1) + endif() + if(CMake_TEST_CTestUpdate_P4) + if(NOT P4_EXECUTABLE OR NOT P4D_EXECUTABLE) + message(FATAL_ERROR "CMake_TEST_CTestUpdate_HG enabled but P4_EXECUTABLE and P4D_EXECUTABLE are not both not found.") endif() + set(CTestUpdateP4_DIR "CTest UpdateP4") + configure_file("${CMake_SOURCE_DIR}/Tests/CTestUpdateP4.cmake.in" + "${CMake_BINARY_DIR}/Tests/CTestUpdateP4.cmake" @ONLY) + add_test(CTest.UpdateP4 ${CMAKE_CMAKE_COMMAND} + -P "${CMake_BINARY_DIR}/Tests/CTestUpdateP4.cmake" + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateP4_DIR}") endif() configure_file( diff --git a/Tests/CMakeTests/FileDownloadTest.cmake.in b/Tests/CMakeTests/FileDownloadTest.cmake.in index e0ce99a..255909d 100644 --- a/Tests/CMakeTests/FileDownloadTest.cmake.in +++ b/Tests/CMakeTests/FileDownloadTest.cmake.in @@ -179,3 +179,51 @@ if(EXISTS TIMEOUT) message(SEND_ERROR "TIMEOUT argument was incorrectly interpreted as a filename") endif() message(STATUS "${status}") + +message(STATUS "FileDownload:14") +file(DOWNLOAD + ${url} + ${dir}/file14.bin + TIMEOUT ${timeout} + STATUS status + RANGE_START 0 + EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92 + ) +__reportIfWrongStatus("${status}" 0) + +message(STATUS "FileDownload:15") +file(DOWNLOAD + ${url} + ${dir}/file15.bin + TIMEOUT ${timeout} + STATUS status + RANGE_END 50 + EXPECTED_MD5 8592e5665b839b5d23825dc84c135b61 + ) +__reportIfWrongStatus("${status}" 0) + +message(STATUS "FileDownload:16") +file(DOWNLOAD + ${url} + ${dir}/file16.bin + TIMEOUT ${timeout} + STATUS status + RANGE_START 10 + RANGE_END 50 + EXPECTED_MD5 36cd52681e6c6c8fef85fcd9e86fc30d + ) +__reportIfWrongStatus("${status}" 0) + +message(STATUS "FileDownload:17") +file(DOWNLOAD + ${url} + ${dir}/file17.bin + TIMEOUT ${timeout} + STATUS status + RANGE_START 0 + RANGE_END 50 + RANGE_START 60 + RANGE_END 100 + EXPECTED_MD5 c5c9e74e82d493dd901eecccd659cebc + ) +__reportIfWrongStatus("${status}" 0) diff --git a/Tests/CTestBuildCommandProjectInSubdir/CTestBuildCommandProjectInSubdir.cmake.in b/Tests/CTestBuildCommandProjectInSubdir/CTestBuildCommandProjectInSubdir.cmake.in deleted file mode 100644 index 0f56781..0000000 --- a/Tests/CTestBuildCommandProjectInSubdir/CTestBuildCommandProjectInSubdir.cmake.in +++ /dev/null @@ -1,11 +0,0 @@ -cmake_minimum_required(VERSION 2.8.10) - -set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/VSProjectInSubdir") -set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestBuildCommandProjectInSubdir/Nested") -set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@") -set(CTEST_BUILD_CONFIGURATION "@CTestTest_CONFIG@") - -ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY}) -ctest_start(Experimental) -ctest_configure(OPTIONS "@ctest_configure_options@") -ctest_build(TARGET test) diff --git a/Tests/ExternalProject/CMakeLists.txt b/Tests/ExternalProject/CMakeLists.txt index 59e3bcc..e4c6c66 100644 --- a/Tests/ExternalProject/CMakeLists.txt +++ b/Tests/ExternalProject/CMakeLists.txt @@ -8,10 +8,50 @@ include(ExternalProject) # Test ExternalProject, especially with checkouts from VCS -find_package(CVS) -find_package(Subversion) -find_package(Git) -find_package(Hg) +if(NOT DEFINED EP_TEST_CVS OR EP_TEST_CVS) + find_package(CVS) +endif() +if(NOT DEFINED EP_TEST_CVS AND CVS_FOUND AND (UNIX OR NOT "${CVS_EXECUTABLE}" MATCHES "cygwin")) + set(EP_TEST_CVS 1) +endif() + +if(NOT DEFINED EP_TEST_SVN OR EP_TEST_SVN) + find_package(Subversion) + if(Subversion_FOUND AND Subversion_VERSION_SVN VERSION_LESS 1.2) + message(STATUS "No ExternalProject svn tests with svn client less than version 1.2") + set(Subversion_FOUND 0) + endif() + # Only do svn tests in cygwin/cygwin or not-cygwin/not-cygwin arrangements: + if(Subversion_FOUND AND CMAKE_CURRENT_BINARY_DIR MATCHES "cygdrive/" AND NOT "${Subversion_SVN_EXECUTABLE}" MATCHES "cygwin") + message(STATUS "No ExternalProject svn tests with non-cygwin svn client in a /cygdrive based build") + set(Subversion_FOUND 0) + endif() +endif() +if(NOT DEFINED EP_TEST_SVN AND Subversion_FOUND) + set(EP_TEST_SVN 1) +endif() + +if(NOT DEFINED EP_TEST_GIT OR EP_TEST_GIT) + find_package(Git) +endif() +if(NOT DEFINED EP_TEST_GIT AND Git_FOUND) + message(STATUS "GIT_VERSION_STRING='${GIT_VERSION_STRING}'") + if(NOT "${GIT_VERSION_STRING}" VERSION_LESS 1.6.5) + set(EP_TEST_GIT 1) + endif() +endif() + +if(NOT DEFINED EP_TEST_HG OR EP_TEST_HG) + find_package(Hg) +endif() +if(NOT DEFINED EP_TEST_HG AND Hg_FOUND) + set(EP_TEST_HG 1) +endif() + +message(STATUS "EP_TEST_CVS='${EP_TEST_CVS}' CVS_EXECUTABLE='${CVS_EXECUTABLE}'") +message(STATUS "EP_TEST_SVN='${EP_TEST_SVN}' Subversion_SVN_EXECUTABLE='${Subversion_SVN_EXECUTABLE}'") +message(STATUS "EP_TEST_GIT='${EP_TEST_GIT}' GIT_EXECUTABLE='${GIT_EXECUTABLE}'") +message(STATUS "EP_TEST_HG='${EP_TEST_HG}' HG_EXECUTABLE='${HG_EXECUTABLE}'") option(ExternalProjectTest_USE_FOLDERS "Enable folder grouping in IDEs." ON) if(ExternalProjectTest_USE_FOLDERS) @@ -115,20 +155,7 @@ ExternalProject_Add(${proj} # CVS-based tests: # -set(do_cvs_tests 0) - -if(CVS_EXECUTABLE) - set(do_cvs_tests 1) -endif() - -if(do_cvs_tests AND NOT UNIX) - if("${CVS_EXECUTABLE}" MATCHES "cygwin") - message(STATUS "No ExternalProject cvs tests with cygwin cvs.exe outside cygwin!") - set(do_cvs_tests 0) - endif() -endif() - -if(do_cvs_tests) +if(EP_TEST_CVS) # Unzip/untar the CVS repository in our source folder so that other # projects below may use it to test CVS args of ExternalProject_Add # @@ -207,32 +234,7 @@ endif() # SVN-based tests: # -set(do_svn_tests 0) - -if(Subversion_SVN_EXECUTABLE) - set(do_svn_tests 1) -endif() - -# Only do svn tests with svn >= version 1.2 -# -if(do_svn_tests) - if(Subversion_VERSION_SVN VERSION_LESS 1.2) - message(STATUS "No ExternalProject svn tests with svn client less than version 1.2") - set(do_svn_tests 0) - endif() -endif() - -# Only do svn tests in cygwin/cygwin or not-cygwin/not-cygwin arrangements: -# -if(do_svn_tests) - if(CMAKE_CURRENT_BINARY_DIR MATCHES "cygdrive/" AND - NOT "${Subversion_SVN_EXECUTABLE}" MATCHES "cygwin") - message(STATUS "No ExternalProject svn tests with non-cygwin svn client in a /cygdrive based build") - set(do_svn_tests 0) - endif() -endif() - -if(do_svn_tests) +if(EP_TEST_SVN) # Unzip/untar the SVN repository in our source folder so that other # projects below may use it to test SVN args of ExternalProject_Add # @@ -292,22 +294,7 @@ if(do_svn_tests) set_property(TARGET ${proj} PROPERTY FOLDER "SVN") endif() - -set(do_git_tests 0) - -if(GIT_EXECUTABLE) - set(do_git_tests 1) - - message(STATUS "GIT_VERSION_STRING='${GIT_VERSION_STRING}'") - - if("${GIT_VERSION_STRING}" VERSION_LESS 1.6.5) - message(STATUS "No ExternalProject git tests with git client less than version 1.6.5") - set(do_git_tests 0) - endif() -endif() - - -if(do_git_tests) +if(EP_TEST_GIT) set(local_git_repo "../../LocalRepositories/GIT") # Unzip/untar the git repository in our source folder so that other @@ -444,7 +431,9 @@ if(do_git_tests) set_property(TARGET ${proj} PROPERTY FOLDER "GIT") set(proj TS1-GIT-all-GIT_SUBMODULES-via-CMP0097-OLD) + set(CMAKE_WARN_DEPRECATED FALSE) # we are testing CMP0097 OLD behavior cmake_policy(SET CMP0097 OLD) + unset(CMAKE_WARN_DEPRECATED) ExternalProject_Add(${proj} GIT_REPOSITORY "${local_git_repo}" GIT_SUBMODULES "" @@ -552,20 +541,7 @@ if(do_git_tests) endif() -set(do_hg_tests 0) - -if(HG_EXECUTABLE) - set(do_hg_tests 1) -endif() - -if(do_hg_tests AND NOT UNIX) - if("${HG_EXECUTABLE}" MATCHES "cygwin") - message(STATUS "No ExternalProject hg tests with cygwin hg outside cygwin!") - set(do_hg_tests 0) - endif() -endif() - -if(do_hg_tests) +if(EP_TEST_HG) set(local_hg_repo "../../LocalRepositories/HG") # Unzip/untar the hg repository in our source folder so that other @@ -640,7 +616,7 @@ enable_testing() # # BuildTree tests: # -if(do_cvs_tests) +if(EP_TEST_CVS) add_test(TutorialStep1-CVS-20090626-BuildTreeTest "${binary_base}/TutorialStep1-CVS-20090626/Tutorial" 4) @@ -651,7 +627,7 @@ if(do_cvs_tests) "${binary_base}/TutorialStep1-CVS-HEAD/Tutorial" 81) endif() -if(do_svn_tests) +if(EP_TEST_SVN) add_test(TutorialStep1-SVN-20090626-BuildTreeTest "${binary_base}/TutorialStep1-SVN-20090626/Tutorial" 100) @@ -662,7 +638,7 @@ if(do_svn_tests) "${binary_base}/TutorialStep1-SVN-trunk/Tutorial" 98) endif() -if(do_git_tests) +if(EP_TEST_GIT) add_test(TutorialStep1-GIT-byhash ${CMAKE_COMMAND} -P "${binary_base}/TutorialStep1-GIT-byhash/example.cmake") @@ -684,13 +660,6 @@ if(do_git_tests) endif() endif() - -message(STATUS "do_cvs_tests='${do_cvs_tests}'") -message(STATUS "do_svn_tests='${do_svn_tests}'") -message(STATUS "do_git_tests='${do_git_tests}' GIT_EXECUTABLE='${GIT_EXECUTABLE}'") -message(STATUS "do_hg_tests='${do_hg_tests}' HG_EXECUTABLE='${HG_EXECUTABLE}'") - - # Test if log works when the first arguments of *_COMMAND is "COMMAND". set(proj ExternalProject-no-log) set(download_cmd "") diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index e97b7dc..eda857b 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -313,6 +313,7 @@ add_RunCMake_test(GenEx-LINK_LANGUAGE) add_RunCMake_test(GenEx-LINK_LANG_AND_ID) add_RunCMake_test(GenEx-HOST_LINK) add_RunCMake_test(GenEx-DEVICE_LINK) +add_RunCMake_test(GenEx-LINK_LIBRARY) add_RunCMake_test(GenEx-TARGET_FILE -DLINKER_SUPPORTS_PDB=${LINKER_SUPPORTS_PDB}) add_RunCMake_test(GenEx-GENEX_EVAL) add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS) @@ -657,6 +658,18 @@ add_RunCMake_test(target_link_libraries) add_RunCMake_test(target_link_libraries-ALIAS) add_RunCMake_test(target_link_libraries-LINK_LANGUAGE) add_RunCMake_test(target_link_libraries-LINK_LANG_AND_ID) +add_RunCMake_test(target_link_libraries-LINK_LIBRARY -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} + -DMINGW=${MINGW} + -DMSYS=${MSYS} + -DCYGWIN=${CYGWIN} + -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID} + -DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION} + -DMSVC_VERSION=${MSVC_VERSION} + -DCMAKE_SHARED_LIBRARY_PREFIX=${CMAKE_SHARED_LIBRARY_PREFIX} + -DCMAKE_SHARED_LIBRARY_SUFFIX=${CMAKE_SHARED_LIBRARY_SUFFIX} + -DCMAKE_IMPORT_LIBRARY_PREFIX=${CMAKE_IMPORT_LIBRARY_PREFIX} + -DCMAKE_IMPORT_LIBRARY_SUFFIX=${CMAKE_IMPORT_LIBRARY_SUFFIX} + -DCMAKE_LINK_LIBRARY_FLAG=${CMAKE_LINK_LIBRARY_FLAG}) add_RunCMake_test(add_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}) add_RunCMake_test(target_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID} -DCMake_TEST_CUDA=${CMake_TEST_CUDA}) @@ -708,7 +721,8 @@ endif() add_executable(pseudo_llvm-rc pseudo_llvm-rc.c) add_RunCMake_test(CommandLine -DLLVM_RC=$<TARGET_FILE:pseudo_llvm-rc> -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} - -DCYGWIN=${CYGWIN} -DMSYS=${MSYS} -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}) + -DCYGWIN=${CYGWIN} -DMSYS=${MSYS} -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} + -DEXIT_CODE_EXE=$<TARGET_FILE:exit_code>) add_RunCMake_test(CommandLineTar) if(CMAKE_PLATFORM_NO_VERSIONED_SONAME OR (NOT CMAKE_SHARED_LIBRARY_SONAME_FLAG AND NOT CMAKE_SHARED_LIBRARY_SONAME_C_FLAG)) @@ -738,6 +752,9 @@ add_RunCMake_test(CPackInstallProperties) if(XCODE_VERSION) set(ExternalProject_ARGS -DXCODE_VERSION=${XCODE_VERSION}) endif() +if(CMake_TEST_RunCMake_ExternalProject_DOWNLOAD_SERVER_TIMEOUT) + list(APPEND ExternalProject_ARGS -DDOWNLOAD_SERVER_TIMEOUT=${CMake_TEST_RunCMake_ExternalProject_DOWNLOAD_SERVER_TIMEOUT}) +endif() add_RunCMake_test(ExternalProject) add_RunCMake_test(FetchContent) set(CTestCommandLine_ARGS -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}) diff --git a/Tests/RunCMake/CommandLine/E_cat-with-double-dash-stdout.txt b/Tests/RunCMake/CommandLine/E_cat-with-double-dash-stdout.txt new file mode 100644 index 0000000..e5939d0 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_cat-with-double-dash-stdout.txt @@ -0,0 +1 @@ +file starting with dash, not an option diff --git a/Tests/RunCMake/CommandLine/E_cat-without-double-dash-result.txt b/Tests/RunCMake/CommandLine/E_cat-without-double-dash-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_cat-without-double-dash-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_cat-without-double-dash-stderr.txt b/Tests/RunCMake/CommandLine/E_cat-without-double-dash-stderr.txt new file mode 100644 index 0000000..051f678 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_cat-without-double-dash-stderr.txt @@ -0,0 +1 @@ +^CMake Error: -file-starting-with-dash.txt: option not handled$ diff --git a/Tests/RunCMake/CommandLine/E_env-with-double-dash-result.txt b/Tests/RunCMake/CommandLine/E_env-with-double-dash-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env-with-double-dash-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/CommandLine/E_env-without-double-dash-result.txt b/Tests/RunCMake/CommandLine/E_env-without-double-dash-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env-without-double-dash-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_env-without-double-dash-stderr.txt b/Tests/RunCMake/CommandLine/E_env-without-double-dash-stderr.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_env-without-double-dash-stderr.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 5944d2d..a09b306 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -684,17 +684,33 @@ file(WRITE "${out}/empty_file.txt" "") file(WRITE "${out}/unicode_file.txt" "à éùç - í•œêµì–´") # Korean in Korean run_cmake_command(E_cat_good_cat ${CMAKE_COMMAND} -E cat "${out}/first_file.txt" "${out}/second_file.txt" "${out}/empty_file.txt" "${out}/unicode_file.txt") -unset(out) run_cmake_command(E_cat_good_binary_cat ${CMAKE_COMMAND} -E cat "${RunCMake_SOURCE_DIR}/E_cat_binary_files/binary.obj" "${RunCMake_SOURCE_DIR}/E_cat_binary_files/binary.obj") +# To test whether the double dash (--) works, we need to control the working directory +# in order to be able to pass a relative path that starts with a dash. +file(WRITE "${out}/-file-starting-with-dash.txt" "file starting with dash, not an option\n") +set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${out}") +run_cmake_command(E_cat-with-double-dash ${CMAKE_COMMAND} -E cat -- "-file-starting-with-dash.txt") +run_cmake_command(E_cat-without-double-dash ${CMAKE_COMMAND} -E cat "-file-starting-with-dash.txt") +unset(RunCMake_TEST_COMMAND_WORKING_DIRECTORY) +unset(out) + run_cmake_command(E_env-no-command0 ${CMAKE_COMMAND} -E env) run_cmake_command(E_env-no-command1 ${CMAKE_COMMAND} -E env TEST_ENV=1) run_cmake_command(E_env-bad-arg1 ${CMAKE_COMMAND} -E env -bad-arg1) run_cmake_command(E_env-set ${CMAKE_COMMAND} -E env TEST_ENV=1 ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-set.cmake) run_cmake_command(E_env-unset ${CMAKE_COMMAND} -E env TEST_ENV=1 ${CMAKE_COMMAND} -E env --unset=TEST_ENV ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-unset.cmake) +# To test whether the double dash (--) works for the env command, we need a command that e.g. contains an equals sign (=) +# and would normally be interpreted as an NAME=VALUE environment variable. +# Ensuring such a command is done by simply copying the trivial exit_code executable with a different name. +cmake_path(GET EXIT_CODE_EXE FILENAME exit_code) +file(COPY_FILE "${EXIT_CODE_EXE}" "${RunCMake_BINARY_DIR}/env=${exit_code}") +run_cmake_command(E_env-with-double-dash ${CMAKE_COMMAND} -E env TEST_ENV=1 -- "${RunCMake_BINARY_DIR}/env=${exit_code}" zero_exit) +run_cmake_command(E_env-without-double-dash ${CMAKE_COMMAND} -E env TEST_ENV=1 "${RunCMake_BINARY_DIR}/env=${exit_code}" zero_exit) + run_cmake_command(E_md5sum-dir ${CMAKE_COMMAND} -E md5sum .) run_cmake_command(E_sha1sum-dir ${CMAKE_COMMAND} -E sha1sum .) run_cmake_command(E_sha224sum-dir ${CMAKE_COMMAND} -E sha224sum .) diff --git a/Tests/RunCMake/CommandLine/trace-json-v1-check.py b/Tests/RunCMake/CommandLine/trace-json-v1-check.py index 1ee005e..2ef1495 100755 --- a/Tests/RunCMake/CommandLine/trace-json-v1-check.py +++ b/Tests/RunCMake/CommandLine/trace-json-v1-check.py @@ -30,6 +30,8 @@ required_traces = [ { 'args': ['STATUS', 'JSON-V1 str', 'spaces'], 'cmd': 'message', + 'line': 1, + 'line_end': 5 }, { 'args': ['ASDF', 'fff', 'sss', ' SPACES !!! '], @@ -46,31 +48,54 @@ required_traces = [ { 'args': msg_args, 'cmd': 'message', - 'frame': 3 if expand else 2 + 'frame': 3 if expand else 2, + 'global_frame': 3 if expand else 2 }, + { + 'args': ['STATUS', 'nested global_frame'], + 'cmd': 'message', + 'frame': 3, + 'global_frame': 6 if expand else 5 + } ] +def assert_fields_look_good(line): + expected_fields = {'args', 'cmd', 'file', 'frame', 'global_frame','line', 'time'} + if "line_end" in line: + assert isinstance(line['line_end'], int) + assert line['line'] != line['line_end'] + expected_fields.add("line_end") + + assert set(line.keys()) == expected_fields + + assert isinstance(line['args'], list) + assert isinstance(line['cmd'], unicode) + assert isinstance(line['file'], unicode) + assert isinstance(line['frame'], int) + assert isinstance(line['global_frame'], int) + assert isinstance(line['line'], int) + assert isinstance(line['time'], float) + + with open(trace_file, 'r') as fp: # Check for version (must be the first document) vers = json.loads(fp.readline()) assert sorted(vers.keys()) == ['version'] assert sorted(vers['version'].keys()) == ['major', 'minor'] assert vers['version']['major'] == 1 - assert vers['version']['minor'] == 1 + assert vers['version']['minor'] == 2 for i in fp.readlines(): line = json.loads(i) - assert sorted(line.keys()) == ['args', 'cmd', 'file', 'frame', 'line', 'time'] - assert isinstance(line['args'], list) - assert isinstance(line['cmd'], unicode) - assert isinstance(line['file'], unicode) - assert isinstance(line['frame'], int) - assert isinstance(line['line'], int) - assert isinstance(line['time'], float) - + assert_fields_look_good(line) for j in required_traces: # Compare the subset of required keys with line - if {k: line[k] for k in j} == j: + subset = { + k: line[k] + for k in j + if k in line + } + if subset == j: required_traces.remove(j) assert not required_traces diff --git a/Tests/RunCMake/CommandLine/trace-json-v1-nested/CMakeLists.txt b/Tests/RunCMake/CommandLine/trace-json-v1-nested/CMakeLists.txt new file mode 100644 index 0000000..089a960 --- /dev/null +++ b/Tests/RunCMake/CommandLine/trace-json-v1-nested/CMakeLists.txt @@ -0,0 +1,9 @@ +function(f) + message(STATUS "nested global_frame") +endfunction() + +function(g) + f() +endfunction() + +g() diff --git a/Tests/RunCMake/CommandLine/trace-json-v1.cmake b/Tests/RunCMake/CommandLine/trace-json-v1.cmake index ed0a0f9..4ed6160 100644 --- a/Tests/RunCMake/CommandLine/trace-json-v1.cmake +++ b/Tests/RunCMake/CommandLine/trace-json-v1.cmake @@ -1,5 +1,10 @@ -message(STATUS "JSON-V1 str" "spaces") +message( + STATUS + "JSON-V1 str" + "spaces" + ) set(ASDF fff sss " SPACES !!! ") set(FOO 42) set(BAR " space in string!") message(STATUS fff ${ASDF} " ${FOO} ${BAR}" " SPACES !!! ") +add_subdirectory(trace-json-v1-nested) diff --git a/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake b/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake index 6dbf0f4..d531928 100644 --- a/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake +++ b/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake @@ -1,5 +1,12 @@ include(ExternalProject) +if(CMAKE_GENERATOR STREQUAL "Borland Makefiles" OR + CMAKE_GENERATOR STREQUAL "Watcom WMake") + set(fs_delay 3) +else() + set(fs_delay 1.125) +endif() + # Given this setup, on the first build, both configure steps and both build # steps will run. On a noop rebuild, only the build steps will run. Without # CONFIGURE_HANDLED_BY_BUILD, the configure step of proj2 would also run on a @@ -11,7 +18,7 @@ ExternalProject_Add(proj1 CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo "Doing something" # file(TIMESTAMP) gives back the timestamp in seconds so we sleep a second to # make sure we get a different timestamp on the stamp file - BUILD_COMMAND ${CMAKE_COMMAND} -E sleep 1.125 + BUILD_COMMAND ${CMAKE_COMMAND} -E sleep ${fs_delay} INSTALL_COMMAND "" BUILD_ALWAYS ON STAMP_DIR "stamp" @@ -20,7 +27,7 @@ ExternalProject_Add(proj2 DOWNLOAD_COMMAND "" SOURCE_DIR "" CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo "Doing something" - BUILD_COMMAND ${CMAKE_COMMAND} -E sleep 1.125 + BUILD_COMMAND ${CMAKE_COMMAND} -E sleep ${fs_delay} INSTALL_COMMAND "" CONFIGURE_HANDLED_BY_BUILD ON DEPENDS proj1 diff --git a/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake b/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake index fde384f..08adee2 100644 --- a/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake +++ b/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake @@ -105,12 +105,15 @@ function(__ep_test_with_build_with_server testName) if(EXISTS "${URL_FILE}") file(REMOVE "${URL_FILE}") endif() + if(NOT DOWNLOAD_SERVER_TIMEOUT) + set(DOWNLOAD_SERVER_TIMEOUT 30) + endif() execute_process( COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/DownloadServer.py --file "${URL_FILE}" ${ARGN} OUTPUT_FILE ${RunCMake_BINARY_DIR}/${testName}-python.txt ERROR_FILE ${RunCMake_BINARY_DIR}/${testName}-python.txt RESULT_VARIABLE result - TIMEOUT 30 + TIMEOUT "${DOWNLOAD_SERVER_TIMEOUT}" ) if(NOT result EQUAL 0) message(FATAL_ERROR "Failed to start download server:\n ${result}") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/CMakeLists.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/CMakeLists.txt new file mode 100644 index 0000000..612169c --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.18...3.22) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake new file mode 100644 index 0000000..d5438b8 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake @@ -0,0 +1,34 @@ +include(RunCMake) + +run_cmake(add_custom_target) +run_cmake(add_custom_command) +run_cmake(add_link_options) +run_cmake(link_directories) +run_cmake(target_link_options) +run_cmake(target_link_directories) +run_cmake(no-arguments) +run_cmake(empty-arguments) +run_cmake(forbidden-arguments) +run_cmake(bad-feature1) +run_cmake(bad-feature2) +run_cmake(bad-feature3) +run_cmake(bad-feature4) +run_cmake(bad-feature5) +run_cmake(bad-feature6) +run_cmake(bad-feature7) +run_cmake(feature-not-supported) +run_cmake(library-ignored) +run_cmake(compatible-features) +run_cmake(incompatible-features1) +run_cmake(incompatible-features2) +run_cmake(incompatible-features3) +run_cmake(nested-compatible-features) +run_cmake(nested-incompatible-features) +run_cmake(only-targets) + +# testing target propertes LINK_LIBRARY_OVERRIDE and LINK_LIBRARY_OVERRIDE_<LIBRARY> +run_cmake(override-features1) +run_cmake(override-features2) +run_cmake(override-features3) +run_cmake(override-features4) +run_cmake(override-features5) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command-stderr.txt new file mode 100644 index 0000000..d8ff0eb --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at add_custom_command.cmake:[0-9]+ \(add_custom_command\): + Error evaluating generator expression: + + \$<LINK_LIBRARY:feat> + + \$<LINK_LIBRARY:...> may only be used with binary targets to specify link + libraries. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command.cmake new file mode 100644 index 0000000..3583a67 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_command.cmake @@ -0,0 +1,4 @@ +add_custom_target(drive) +add_custom_command(TARGET drive PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "$<LINK_LIBRARY:feat>" +) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target-stderr.txt new file mode 100644 index 0000000..8ca384d --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at add_custom_target.cmake:[0-9]+ \(add_custom_target\): + Error evaluating generator expression: + + \$<LINK_LIBRARY:feat> + + \$<LINK_LIBRARY:...> may only be used with binary targets to specify link + libraries. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target.cmake new file mode 100644 index 0000000..ef00965 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_custom_target.cmake @@ -0,0 +1,3 @@ +add_custom_target(drive + COMMAND ${CMAKE_COMMAND} -E echo "$<LINK_LIBRARY:feat>" +) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options-stderr.txt new file mode 100644 index 0000000..399a413 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at add_link_options.cmake:[0-9]+ \(add_link_options\): + Error evaluating generator expression: + + \$<LINK_LIBRARY:feat> + + \$<LINK_LIBRARY:...> may only be used with binary targets to specify link + libraries. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options.cmake new file mode 100644 index 0000000..fdccf95 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/add_link_options.cmake @@ -0,0 +1,5 @@ +enable_language(C) + +add_link_options("$<LINK_LIBRARY:feat>") + +add_library(empty SHARED empty.c) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1-stderr.txt new file mode 100644 index 0000000..0ff8aca --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at bad-feature1.cmake:[0-9]+ \(add_library\): + Feature 'bad_feat', specified through generator-expression + '\$<LINK_LIBRARY>' to link target 'lib', is not supported for the 'C' link + language. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1.cmake new file mode 100644 index 0000000..5e540cf --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature1.cmake @@ -0,0 +1,6 @@ +enable_language(C) + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:bad_feat,dep>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2-stderr.txt new file mode 100644 index 0000000..9e878cc --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2-stderr.txt @@ -0,0 +1,5 @@ +CMake Error at bad-feature2.cmake:[0-9]+ \(add_library\): + Feature 'feat', specified through generator-expression '\$<LINK_LIBRARY>' to + link target 'lib', is not defined for the 'C' link language. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2.cmake new file mode 100644 index 0000000..2c9efce --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature2.cmake @@ -0,0 +1,8 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat_SUPPORTED TRUE) + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feat,dep>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3-stderr.txt new file mode 100644 index 0000000..48cf51e --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at bad-feature3.cmake:[0-9]+ \(add_library\): + Feature 'feat', specified by variable 'CMAKE_C_LINK_LIBRARY_USING_feat', is + malformed \("<LIBRARY>", "<LIB_ITEM>", or "<LINK_ITEM>" patterns are + missing\) and cannot be used to link target 'lib'. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3.cmake new file mode 100644 index 0000000..dab6a64 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature3.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat "") + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feat,dep>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4-stderr.txt new file mode 100644 index 0000000..c074dd0 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at bad-feature4.cmake:[0-9]+ \(add_library\): + Feature 'feat', specified by variable 'CMAKE_C_LINK_LIBRARY_USING_feat', is + malformed \("<LIBRARY>", "<LIB_ITEM>", or "<LINK_ITEM>" patterns are + missing\) and cannot be used to link target 'lib'. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4.cmake new file mode 100644 index 0000000..6942f7c --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature4.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat "-opt") + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feat,dep>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5-stderr.txt new file mode 100644 index 0000000..6604307 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at bad-feature5.cmake:[0-9]+ \(add_library\): + Feature 'feat', specified by variable 'CMAKE_C_LINK_LIBRARY_USING_feat', is + malformed \(wrong number of elements\) and cannot be used to link target + 'lib'. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5.cmake new file mode 100644 index 0000000..d0a827a --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature5.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat "-prefix" "<LIBRARY>") + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feat,dep>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6-stderr.txt new file mode 100644 index 0000000..9de4ffa --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at bad-feature6.cmake:[0-9]+ \(add_library\): + Feature 'feat', specified by variable 'CMAKE_C_LINK_LIBRARY_USING_feat', is + malformed \("<LIBRARY>", "<LIB_ITEM>", or "<LINK_ITEM>" patterns are missing + for "PATH{}" alternative\) and cannot be used to link target 'lib'. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6.cmake new file mode 100644 index 0000000..04a50f8 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature6.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat "PATH{}NAME{<LIBRARY>}") + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feat,dep>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7-stderr.txt new file mode 100644 index 0000000..9ea9936 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at bad-feature7.cmake:[0-9]+ \(add_library\): + Feature 'feat', specified by variable 'CMAKE_C_LINK_LIBRARY_USING_feat', is + malformed \("<LIBRARY>", "<LIB_ITEM>", or "<LINK_ITEM>" patterns are missing + for "NAME{}" alternative\) and cannot be used to link target 'lib'. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7.cmake new file mode 100644 index 0000000..9659811 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature7.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat "NAME{}PATH{<LIBRARY>}") + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feat,dep>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/compatible-features.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/compatible-features.cmake new file mode 100644 index 0000000..fb88e36 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/compatible-features.cmake @@ -0,0 +1,21 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat1 "<LIBRARY>") + +set(CMAKE_C_LINK_LIBRARY_USING_feat2_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat2 "<LIBRARY>") + +add_library(dep1 SHARED empty.c) + +add_library(dep2 SHARED empty.c) +target_link_libraries(dep2 PRIVATE "$<LINK_LIBRARY:feat1,dep1>") + +add_library(dep3 SHARED empty.c) +target_link_libraries(dep3 PUBLIC dep2) + +add_library(lib1 SHARED empty.c) +target_link_libraries(lib1 PRIVATE "$<LINK_LIBRARY:feat2,dep1,dep2>") + +add_library(lib2 SHARED empty.c) +target_link_libraries(lib2 PRIVATE "$<LINK_LIBRARY:DEFAULT,dep2,dep3>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments-stderr.txt new file mode 100644 index 0000000..1530f61 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at empty-arguments.cmake:[0-9]+ \(target_link_libraries\): + Error evaluating generator expression: + + \$<LINK_LIBRARY:,> + + \$<LINK_LIBRARY:...> expects a feature name as first argument. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments.cmake new file mode 100644 index 0000000..c6e2260 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty-arguments.cmake @@ -0,0 +1,4 @@ +enable_language(C) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:,>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/empty.c b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/empty.c diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported-stderr.txt new file mode 100644 index 0000000..6067bce --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported-stderr.txt @@ -0,0 +1,5 @@ +CMake Error at feature-not-supported.cmake:[0-9]+ \(add_library\): + Feature 'feat', specified through generator-expression '\$<LINK_LIBRARY>' to + link target 'lib', is not supported for the 'C' link language. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported.cmake new file mode 100644 index 0000000..0d952c2 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/feature-not-supported.cmake @@ -0,0 +1,9 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat_SUPPORTED FALSE) +set(CMAKE_C_LINK_LIBRARY_USING_feat "<LIBRARY>") + +add_library(dep SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feat,dep>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments-stderr.txt new file mode 100644 index 0000000..5245dd8 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments-stderr.txt @@ -0,0 +1,16 @@ +CMake Error at forbidden-arguments.cmake:[0-9]+ \(link_libraries\): + Property LINK_LIBRARIES contains the invalid item "<LINK_LIBRARY:feat>". + The LINK_LIBRARIES property may contain the generator-expression + "\$<LINK_LIBRARY:...>" which may be used to specify how the libraries are + linked. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) + + +CMake Error at forbidden-arguments.cmake:[0-9]+ \(target_link_libraries\): + Property LINK_LIBRARIES contains the invalid item "<LINK_LIBRARY:feat>". + The LINK_LIBRARIES property may contain the generator-expression + "\$<LINK_LIBRARY:...>" which may be used to specify how the libraries are + linked. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments.cmake new file mode 100644 index 0000000..1c51c44 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/forbidden-arguments.cmake @@ -0,0 +1,6 @@ +enable_language(C) + +link_libraries(<LINK_LIBRARY:feat> foo </LINK_LIBRARY:feat>) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE <LINK_LIBRARY:feat> foo </LINK_LIBRARY:feat>) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-stderr.txt new file mode 100644 index 0000000..1b31faa --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at incompatible-features1.cmake:[0-9]+ \(add_library\): + Impossible to link target 'lib' because the link item 'dep1', specified + with the feature 'feat1', has already occurred with the feature 'feat2', + which is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1.cmake new file mode 100644 index 0000000..c230c4f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features1.cmake @@ -0,0 +1,15 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat1 "<LIBRARY>") + +set(CMAKE_C_LINK_LIBRARY_USING_feat2_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat2 "<LIBRARY>") + +add_library(dep1 SHARED empty.c) + +add_library(dep2 SHARED empty.c) +target_link_libraries(dep2 PUBLIC "$<LINK_LIBRARY:feat1,dep1>") + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feat2,dep1,dep2>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-stderr.txt new file mode 100644 index 0000000..0855481 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at incompatible-features2.cmake:[0-9]+ \(add_library\): + Impossible to link target 'lib' because the link item 'dep1', specified + without any feature or 'DEFAULT' feature, has already occurred with the + feature 'feat2', which is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2.cmake new file mode 100644 index 0000000..d204ebd --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features2.cmake @@ -0,0 +1,15 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat1 "<LIBRARY>") + +set(CMAKE_C_LINK_LIBRARY_USING_feat2_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat2 "<LIBRARY>") + +add_library(dep1 SHARED empty.c) + +add_library(dep2 SHARED empty.c) +target_link_libraries(dep2 PUBLIC dep1) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feat2,dep1,dep2>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-stderr.txt new file mode 100644 index 0000000..2f40a1d --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at incompatible-features3.cmake:[0-9]+ \(add_library\): + Impossible to link target 'lib' because the link item 'dep1', specified + with the feature 'feat1', has already occurred without any feature or + 'DEFAULT' feature, which is not allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3.cmake new file mode 100644 index 0000000..bf79e11 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/incompatible-features3.cmake @@ -0,0 +1,15 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat1 "<LIBRARY>") + +set(CMAKE_C_LINK_LIBRARY_USING_feat2_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat2 "<LIBRARY>") + +add_library(dep1 SHARED empty.c) + +add_library(dep2 SHARED empty.c) +target_link_libraries(dep2 PUBLIC "$<LINK_LIBRARY:feat1,dep1>") + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE dep1 dep2) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored-stderr.txt new file mode 100644 index 0000000..f9a99af --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored-stderr.txt @@ -0,0 +1,14 @@ +CMake Warning \(dev\) at library-ignored.cmake:[0-9]+ \(add_library\): + The feature 'feat', specified as part of a generator-expression + '\$<LINK_LIBRARY:feat>', will not be applied to the INTERFACE library + 'front'. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning \(dev\) at library-ignored.cmake:[0-9]+ \(add_library\): + The feature 'feat', specified as part of a generator-expression + '\$<LINK_LIBRARY:feat>', will not be applied to the OBJECT library 'dep'. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored.cmake new file mode 100644 index 0000000..a888bb8 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored.cmake @@ -0,0 +1,15 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat "<LIBRARY>") + +add_library(dep OBJECT empty.c) + +add_library(lib SHARED empty.c) + +add_library(front INTERFACE) +target_link_libraries(front INTERFACE lib) + + +add_library(lib2 SHARED empty.c) +target_link_libraries(lib2 PRIVATE "$<LINK_LIBRARY:feat,front,dep>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories-stderr.txt new file mode 100644 index 0000000..aeb32f2 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at link_directories.cmake:[0-9]+ \(link_directories\): + Error evaluating generator expression: + + \$<LINK_LIBRARY:feat> + + \$<LINK_LIBRARY:...> may only be used with binary targets to specify link + libraries. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories.cmake new file mode 100644 index 0000000..b6d9a36 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/link_directories.cmake @@ -0,0 +1,5 @@ +enable_language(C) + +link_directories("$<LINK_LIBRARY:feat>") + +add_library(empty SHARED empty.c) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-compatible-features.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-compatible-features.cmake new file mode 100644 index 0000000..561aa09 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-compatible-features.cmake @@ -0,0 +1,11 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat1 "<LIBRARY>") + +add_library(dep1 SHARED empty.c) + +add_library(dep2 SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feat1,dep1,$<LINK_LIBRARY:feat1,dep2>>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features-stderr.txt new file mode 100644 index 0000000..3f6c504 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at nested-incompatible-features.cmake:[0-9]+ \(target_link_libraries\): + Error evaluating generator expression: + + \$<LINK_LIBRARY:feat2,dep1,\$<LINK_LIBRARY:feat1,dep2>> + + \$<LINK_LIBRARY:...> with different features cannot be nested. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features.cmake new file mode 100644 index 0000000..746638e --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/nested-incompatible-features.cmake @@ -0,0 +1,14 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat1 "<LIBRARY>") + +set(CMAKE_C_LINK_LIBRARY_USING_feat2_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat2 "<LIBRARY>") + +add_library(dep1 SHARED empty.c) + +add_library(dep2 SHARED empty.c) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feat2,dep1,$<LINK_LIBRARY:feat1,dep2>>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments-stderr.txt new file mode 100644 index 0000000..af58fa0 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at no-arguments.cmake:[0-9]+ \(target_link_libraries\): + Error evaluating generator expression: + + \$<LINK_LIBRARY> + + \$<LINK_LIBRARY> expression requires at least one parameter. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments.cmake new file mode 100644 index 0000000..0645dc7 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/no-arguments.cmake @@ -0,0 +1,4 @@ +enable_language(C) + +add_library(lib SHARED empty.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets-stderr.txt new file mode 100644 index 0000000..6b770f0 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets-stderr.txt @@ -0,0 +1,13 @@ +CMake Error at only-targets.cmake:[0-9]+ \(target_link_libraries\): + Target "lib2" has LINK_LIBRARIES_ONLY_TARGETS enabled, but it links to: + + external + + which is not a target. Possible reasons include: + + \* There is a typo in the target name. + \* A find_package call is missing for an IMPORTED target. + \* An ALIAS target is missing. + +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets.cmake new file mode 100644 index 0000000..8cec0c3 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/only-targets.cmake @@ -0,0 +1,16 @@ +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_feat1_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat1 "<LIBRARY>") + +set(CMAKE_LINK_LIBRARIES_ONLY_TARGETS 1) + +add_library(dep1 SHARED empty.c) + +add_library(lib1 SHARED empty.c) +# accepted +target_link_libraries(lib1 PRIVATE "$<LINK_LIBRARY:feat1,dep1>") + +add_library(lib2 SHARED empty.c) +# invalid +target_link_libraries(lib2 PRIVATE "$<LINK_LIBRARY:feat1,external>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features1.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features1.cmake new file mode 100644 index 0000000..6306c5d --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features1.cmake @@ -0,0 +1,4 @@ + +include(incompatible-features1.cmake) + +set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE "feat1,dep1") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features2.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features2.cmake new file mode 100644 index 0000000..aa6ee76 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features2.cmake @@ -0,0 +1,4 @@ + +include(incompatible-features1.cmake) + +set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE "feat2,dep1") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features3.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features3.cmake new file mode 100644 index 0000000..a1437e6 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features3.cmake @@ -0,0 +1,7 @@ + +include(incompatible-features1.cmake) + +set(CMAKE_C_LINK_LIBRARY_USING_feat3_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat3 "<LIBRARY>") + +set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE "feat3,dep1") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features4.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features4.cmake new file mode 100644 index 0000000..f34f745 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features4.cmake @@ -0,0 +1,9 @@ + +include(incompatible-features1.cmake) + + +set(CMAKE_C_LINK_LIBRARY_USING_feat3_SUPPORTED TRUE) +set(CMAKE_C_LINK_LIBRARY_USING_feat3 "<LIBRARY>") + +set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE "feat3,dep1") +set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE_dep1 feat1) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features5.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features5.cmake new file mode 100644 index 0000000..1406d2a --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/override-features5.cmake @@ -0,0 +1,7 @@ + +include(incompatible-features1.cmake) + + +set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE "feat1,dep1") +# next property will be ignored because no feature is specified +set_property(TARGET lib PROPERTY LINK_LIBRARY_OVERRIDE_dep1) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories-stderr.txt new file mode 100644 index 0000000..e0c60c4 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at target_link_directories.cmake:[0-9]+ \(target_link_directories\): + Error evaluating generator expression: + + \$<LINK_LIBRARY:feat> + + \$<LINK_LIBRARY:...> may only be used with binary targets to specify link + libraries. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories.cmake new file mode 100644 index 0000000..e8cc670 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_directories.cmake @@ -0,0 +1,4 @@ +enable_language(C) + +add_library(empty SHARED empty.c) +target_link_directories(empty PRIVATE "$<LINK_LIBRARY:feat>") diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options-stderr.txt new file mode 100644 index 0000000..6c9aab1 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at target_link_options.cmake:[0-9]+ \(target_link_options\): + Error evaluating generator expression: + + \$<LINK_LIBRARY:FEAT> + + \$<LINK_LIBRARY:...> may only be used with binary targets to specify link + libraries. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options.cmake new file mode 100644 index 0000000..a989a53 --- /dev/null +++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/target_link_options.cmake @@ -0,0 +1,4 @@ +enable_language(C) + +add_library(empty SHARED empty.c) +target_link_options(empty PRIVATE "$<LINK_LIBRARY:FEAT>") diff --git a/Tests/RunCMake/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake index 9f692ee..3066cc1 100644 --- a/Tests/RunCMake/RunCMake.cmake +++ b/Tests/RunCMake/RunCMake.cmake @@ -164,6 +164,7 @@ function(run_cmake test) "|[^\n]*install_name_tool: warning: changes being made to the file will invalidate the code signature in:" "|[^\n]*xcodebuild[^\n]*DVTPlugInManager" + "|[^\n]*xcodebuild[^\n]*Requested but did not find extension point with identifier" "|[^\n]*xcodebuild[^\n]*warning: file type[^\n]*is based on missing file type" "|[^\n]*objc[^\n]*: Class AMSupportURL[^\n]* One of the two will be used. Which one is undefined." "|[^\n]*is a member of multiple groups" diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index 139dcc7..b19c1a8 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -84,3 +84,4 @@ endif() run_cmake(VsDotnetTargetFramework) run_cmake(VsDotnetTargetFrameworkVersion) +run_cmake(VsNoCompileBatching) diff --git a/Tests/RunCMake/VS10Project/VsNoCompileBatching-check.cmake b/Tests/RunCMake/VS10Project/VsNoCompileBatching-check.cmake new file mode 100644 index 0000000..4002c3f --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsNoCompileBatching-check.cmake @@ -0,0 +1,31 @@ +macro(VsNoCompileBatching_check tgt ofn_expect) + set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/${tgt}.vcxproj") + if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not exist.") + return() + endif() + + set(HAVE_OFN 0) + + file(STRINGS "${vcProjectFile}" lines) + foreach(line IN LISTS lines) + if(line MATCHES "^ *<ObjectFileName>([^<>]+)</ObjectFileName>") + set(ofn_actual "${CMAKE_MATCH_1}") + if(NOT "${ofn_actual}" STREQUAL "${ofn_expect}") + set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has <ObjectFileName> '${ofn_actual}', not '${ofn_expect}'.") + return() + endif() + set(HAVE_OFN 1) + break() + endif() + endforeach() + + if(NOT HAVE_OFN) + set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a <ObjectFileName> property.") + return() + endif() +endmacro() + +VsNoCompileBatching_check(foo "$(IntDir)") +VsNoCompileBatching_check(foo_NB "$(IntDir)%(filename).obj") +VsNoCompileBatching_check(foo_NB_OFF "$(IntDir)") diff --git a/Tests/RunCMake/VS10Project/VsNoCompileBatching.cmake b/Tests/RunCMake/VS10Project/VsNoCompileBatching.cmake new file mode 100644 index 0000000..c96edce --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsNoCompileBatching.cmake @@ -0,0 +1,9 @@ +enable_language(CXX) + +add_library(foo foo.cpp) + +add_library(foo_NB foo.cpp) +set_property(TARGET foo_NB PROPERTY VS_NO_COMPILE_BATCHING ON) + +add_library(foo_NB_OFF foo.cpp) +set_property(TARGET foo_NB_OFF PROPERTY VS_NO_COMPILE_BATCHING OFF) diff --git a/Tests/RunCMake/cmake_language/defer_call_trace_json-stderr.txt b/Tests/RunCMake/cmake_language/defer_call_trace_json-stderr.txt index 647beb0..3bde16d 100644 --- a/Tests/RunCMake/cmake_language/defer_call_trace_json-stderr.txt +++ b/Tests/RunCMake/cmake_language/defer_call_trace_json-stderr.txt @@ -1,5 +1,5 @@ -{"args":\["DEFER","CALL","message","Deferred Message"\],"cmd":"cmake_language","file":"[^"]*/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake","frame":2,"line":2,"time":[0-9.]+} -{"args":\["Immediate Message"\],"cmd":"message","file":"[^"]*/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake","frame":2,"line":3,"time":[0-9.]+} +{"args":\["DEFER","CALL","message","Deferred Message"\],"cmd":"cmake_language","file":"[^"]*/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake","frame":2,"global_frame":2,"line":2,"time":[0-9.]+} +{"args":\["Immediate Message"\],"cmd":"message","file":"[^"]*/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake","frame":2,"global_frame":2,"line":3,"time":[0-9.]+} Immediate Message -{"args":\["Deferred Message"],"cmd":"message","defer":"__0","file":"[^"]*/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake","frame":1,"line":2,"time":[0-9.]+} +{"args":\["Deferred Message"],"cmd":"message","defer":"__0","file":"[^"]*/Tests/RunCMake/cmake_language/defer_call_trace_json.cmake","frame":1,"global_frame":1,"line":2,"time":[0-9.]+} Deferred Message$ diff --git a/Tests/RunCMake/ctest_build/RunCMakeTest.cmake b/Tests/RunCMake/ctest_build/RunCMakeTest.cmake index 511cd71..e94a55d 100644 --- a/Tests/RunCMake/ctest_build/RunCMakeTest.cmake +++ b/Tests/RunCMake/ctest_build/RunCMakeTest.cmake @@ -49,6 +49,18 @@ function(run_BuildChangeId) endfunction() run_BuildChangeId() +function(run_SubdirTarget) + set(CASE_CMAKELISTS_SUFFIX_CODE [=[ +file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/subdir/CMakeLists.txt [[ +add_custom_target(target_in_subdir COMMAND ${CMAKE_COMMAND} -E touch target_in_subdir.out VERBATIM) +]]) +add_subdirectory(subdir) +]=]) + set(CASE_CTEST_BUILD_ARGS TARGET target_in_subdir) + run_ctest(SubdirTarget) +endfunction() +run_SubdirTarget() + set(RunCMake_USE_CUSTOM_BUILD_COMMAND TRUE) set(RunCMake_BUILD_COMMAND "${FAKE_BUILD_COMMAND_EXE}") run_ctest(BuildCommandFailure) diff --git a/Tests/RunCMake/ctest_build/SubdirTarget-check.cmake b/Tests/RunCMake/ctest_build/SubdirTarget-check.cmake new file mode 100644 index 0000000..81d21ec --- /dev/null +++ b/Tests/RunCMake/ctest_build/SubdirTarget-check.cmake @@ -0,0 +1,4 @@ +set(expected_file "${RunCMake_TEST_BINARY_DIR}/subdir/target_in_subdir.out") +if(NOT EXISTS "${expected_file}") + set(RunCMake_TEST_FAILED "Expected build output file not found:\n ${expected_file}") +endif() diff --git a/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-stderr.txt b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-stderr.txt index 2561263..8b0970a 100644 --- a/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-stderr.txt +++ b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-stderr.txt @@ -1,3 +1,15 @@ +^CMake Deprecation Warning at TARGETS-FILE_RPATH_CHANGE-new_rpath.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0095 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + TARGETS-FILE_RPATH_CHANGE-new_rpath.cmake:[0-9]+ \(A_CMP0095\) + CMakeLists.txt:[0-9]+ \(include\)( ++ CMake Warning \(dev\) at TARGETS-FILE_RPATH_CHANGE-new_rpath\.cmake:[0-9]+ \(install\): Policy CMP0095 is not set: RPATH entries are properly escaped in the intermediary CMake install script\. Run "cmake --help-policy CMP0095" for @@ -8,8 +20,8 @@ CMake Warning \(dev\) at TARGETS-FILE_RPATH_CHANGE-new_rpath\.cmake:[0-9]+ \(ins intermediary cmake_install\.cmake script\. Call Stack \(most recent call first\): CMakeLists\.txt:[0-9]+ \(include\) -This warning is for project developers\. Use -Wno-dev to suppress it\. - +This warning is for project developers\. Use -Wno-dev to suppress it\.)+( ++ CMake Warning \(dev\) at TARGETS-FILE_RPATH_CHANGE-new_rpath\.cmake:[0-9]+ \(install\): Policy CMP0095 is not set: RPATH entries are properly escaped in the intermediary CMake install script\. Run "cmake --help-policy CMP0095" for @@ -20,4 +32,4 @@ CMake Warning \(dev\) at TARGETS-FILE_RPATH_CHANGE-new_rpath\.cmake:[0-9]+ \(ins intermediary cmake_install\.cmake script\. Call Stack \(most recent call first\): CMakeLists\.txt:[0-9]+ \(include\) -This warning is for project developers\. Use -Wno-dev to suppress it\. +This warning is for project developers\. Use -Wno-dev to suppress it\.)+$ diff --git a/Tests/RunCMake/project/CMP0096-OLD-stderr.txt b/Tests/RunCMake/project/CMP0096-OLD-stderr.txt new file mode 100644 index 0000000..beb7a84 --- /dev/null +++ b/Tests/RunCMake/project/CMP0096-OLD-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at CMP0096-OLD.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0096 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/project/VersionMax-stderr.txt b/Tests/RunCMake/project/VersionMax-stderr.txt new file mode 100644 index 0000000..b789640 --- /dev/null +++ b/Tests/RunCMake/project/VersionMax-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at VersionMax.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0096 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/CMakeLists.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/CMakeLists.txt new file mode 100644 index 0000000..915fc41 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.1...3.22) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE) diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group1-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group1-check.cmake new file mode 100644 index 0000000..255c9a6 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group1-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base2${LINK_SHARED_LIBRARY_SUFFIX}") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG<base1> --LIBFLAG<base2>'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group1-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group1-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group1-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group2-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group2-check.cmake new file mode 100644 index 0000000..a8e0da7 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group2-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base2${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --LIBGROUP<base1> --LIBGROUP<base2> --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group2-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group2-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-group2-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items1-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items1-check.cmake new file mode 100644 index 0000000..54cef2c --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items1-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?${CMAKE_LINK_LIBRARY_FLAG}other${LINK_EXTERN_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP <base1> <other> --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items1-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items1-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items1-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items2-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items2-check.cmake new file mode 100644 index 0000000..7c38134 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items2-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBGROUPother${LINK_EXTERN_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --LIBGROUP<base1> --LIBGROUP<other> --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items2-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items2-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items2-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items3-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items3-check.cmake new file mode 100644 index 0000000..88b5cf6 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items3-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-ITEMFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBFLAGother${LINK_EXTERN_LIBRARY_SUFFIX}\"? +\"?(/|-)-ITEMFLAGother\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --LIBFLAG<base1> --ITEMFLAG<base1> --LIBFLAG<other> --ITEMFLAG<other> --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items3-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items3-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items3-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items4-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items4-check.cmake new file mode 100644 index 0000000..c473637 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items4-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-ITEMFLAGother\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --LIBFLAG<base1> --ITEMFLAG<other> --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items4-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items4-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-link-items4-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features1-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features1-check.cmake new file mode 100644 index 0000000..858dcfe --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features1-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --LIBGROUP<base1> --LIBGROUP<base3> --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features1-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features1-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features1-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features2-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features2-check.cmake new file mode 100644 index 0000000..ab06726 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features2-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --LIBGROUP<base3> --LIBGROUP<base1> --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features2-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features2-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features2-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features3-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features3-check.cmake new file mode 100644 index 0000000..62aa17c --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features3-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "${LINK_SHARED_LIBRARY_PREFIX}base2${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP\"? +\"?${CMAKE_LINK_LIBRARY_FLAG}other2${LINK_EXTERN_LIBRARY_SUFFIX}\"? +\"?(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP\"? +\"?${CMAKE_LINK_LIBRARY_FLAG}other1${LINK_EXTERN_LIBRARY_SUFFIX}") + set (RunCMake_TEST_FAILED "Not found expected '<base2> --PREFIXGROUP --LIBGROUP<base3> --SUFFIXGROUP <other2> --PREFIXGROUP --LIBGROUP<base1> --SUFFIXGROUP <other1>'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features3-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features3-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-mix-features3-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature1-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature1-check.cmake new file mode 100644 index 0000000..255c9a6 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature1-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base2${LINK_SHARED_LIBRARY_SUFFIX}") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG<base1> --LIBFLAG<base2>'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature1-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature1-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature1-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature2-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature2-check.cmake new file mode 100644 index 0000000..a8e0da7 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature2-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base2${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--PREFIXGROUP --LIBGROUP<base1> --LIBGROUP<base2> --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature2-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature2-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-nested-feature2-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-check.cmake new file mode 100644 index 0000000..a9fba20 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?${CMAKE_LINK_LIBRARY_FLAG}other1") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG<base3> --LIBFLAG<base1> <other1>'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features1-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-check.cmake new file mode 100644 index 0000000..58c117e --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBGROUPother1${LINK_EXTERN_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG<base3> --PREFIXGROUP --LIBGROUP<base1> --LIBGROUP<other1> --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features2-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-check.cmake new file mode 100644 index 0000000..a9fba20 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?${CMAKE_LINK_LIBRARY_FLAG}other1") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG<base3> --LIBFLAG<base1> <other1>'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features3-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-check.cmake new file mode 100644 index 0000000..58c117e --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-PREFIXGROUP\"? +\"?(/|-)-LIBGROUP.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?(/|-)-LIBGROUPother1${LINK_EXTERN_LIBRARY_SUFFIX}\"? +\"?(/|-)-SUFFIXGROUP") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG<base3> --PREFIXGROUP --LIBGROUP<base1> --LIBGROUP<other1> --SUFFIXGROUP'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-features4-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-check.cmake new file mode 100644 index 0000000..d022f7e --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base3${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?.*${LINK_SHARED_LIBRARY_PREFIX}base1${LINK_SHARED_LIBRARY_SUFFIX}\"? +\"?${CMAKE_LINK_LIBRARY_FLAG}other1${LINK_EXTERN_LIBRARY_SUFFIX}\"?") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG<base3> <base1> <other1>'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-override-with-DEFAULT-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple1-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple1-check.cmake new file mode 100644 index 0000000..32b58fe --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple1-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG<base1>'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple1-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple1-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple1-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple2-check.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple2-check.cmake new file mode 100644 index 0000000..32b58fe --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple2-check.cmake @@ -0,0 +1,4 @@ + +if (NOT actual_stdout MATCHES "(/|-)-LIBFLAG.*${LINK_SHARED_LIBRARY_PREFIX}base1") + set (RunCMake_TEST_FAILED "Not found expected '--LIBFLAG<base1>'.") +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple2-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple2-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY-simple2-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY.cmake new file mode 100644 index 0000000..1581611 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/LINK_LIBRARY.cmake @@ -0,0 +1,104 @@ +enable_language(C) + +# ensure command line is always displayed and do not use any response file +set(CMAKE_VERBOSE_MAKEFILE TRUE) +set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES FALSE) + +if (CMAKE_GENERATOR MATCHES "Borland|NMake") + string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}") + string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}") +endif() + +add_library(base1 SHARED base.c) +add_library(base2 SHARED base.c) + +set(CMAKE_C_LINK_LIBRARY_USING_feat1 "--LIBFLAG<LIBRARY>") +set(CMAKE_C_LINK_LIBRARY_USING_feat1_SUPPORTED TRUE) + +set(CMAKE_C_LINK_LIBRARY_USING_feat1_1 "--LIBFLAG_C<LIBRARY>") +set(CMAKE_C_LINK_LIBRARY_USING_feat1_1_SUPPORTED FALSE) +set(CMAKE_LINK_LIBRARY_USING_feat1_1 "--LIBFLAG<LIBRARY>") +set(CMAKE_LINK_LIBRARY_USING_feat1_1_SUPPORTED TRUE) + +set(CMAKE_C_LINK_LIBRARY_USING_feat2 "--PREFIXGROUP" "--LIBGROUP<LIBRARY>" "--SUFFIXGROUP") +set(CMAKE_C_LINK_LIBRARY_USING_feat2_SUPPORTED TRUE) + +set(CMAKE_C_LINK_LIBRARY_USING_feat3 "--PREFIXGROUP" "<LINK_ITEM>" "--SUFFIXGROUP") +set(CMAKE_C_LINK_LIBRARY_USING_feat3_SUPPORTED TRUE) + +set(CMAKE_C_LINK_LIBRARY_USING_feat4 "--PREFIXGROUP" "--LIBFLAG<LIBRARY> --ITEMFLAG<LIB_ITEM>" "--SUFFIXGROUP") +set(CMAKE_C_LINK_LIBRARY_USING_feat4_SUPPORTED TRUE) + +set(CMAKE_C_LINK_LIBRARY_USING_feat5 "--PREFIXGROUP" "PATH{--LIBFLAG<LIBRARY>}NAME{--ITEMFLAG<LIB_ITEM>}" "--SUFFIXGROUP") +set(CMAKE_C_LINK_LIBRARY_USING_feat5_SUPPORTED TRUE) + +set(CMAKE_C_LINK_LIBRARY_USING_feat6 "<LINK_ITEM>") +set(CMAKE_C_LINK_LIBRARY_USING_feat6_SUPPORTED TRUE) + + +add_library(LinkLibrary_simple1 SHARED lib.c) +target_link_libraries(LinkLibrary_simple1 PRIVATE "$<LINK_LIBRARY:feat1,base1>") + +add_library(LinkLibrary_simple2 SHARED lib.c) +target_link_libraries(LinkLibrary_simple2 PRIVATE "$<LINK_LIBRARY:feat1_1,base1>") + +add_library(LinkLibrary_group1 SHARED lib.c) +target_link_libraries(LinkLibrary_group1 PRIVATE "$<LINK_LIBRARY:feat1,base1,base2>") + +add_library(LinkLibrary_group2 SHARED lib.c) +target_link_libraries(LinkLibrary_group2 PRIVATE "$<LINK_LIBRARY:feat2,base1,base2>") + +add_library(LinkLibrary_nested_feature1 SHARED lib.c) +target_link_libraries(LinkLibrary_nested_feature1 PRIVATE "$<LINK_LIBRARY:feat1,base1,$<LINK_LIBRARY:feat1,base2>>") + +add_library(LinkLibrary_nested_feature2 SHARED lib.c) +target_link_libraries(LinkLibrary_nested_feature2 PRIVATE "$<LINK_LIBRARY:feat2,base1,$<LINK_LIBRARY:feat2,base2>>") + +add_library(LinkLibrary_link_items1 SHARED lib.c) +target_link_libraries(LinkLibrary_link_items1 PRIVATE "$<LINK_LIBRARY:feat3,base1,other>") + +add_library(LinkLibrary_link_items2 SHARED lib.c) +target_link_libraries(LinkLibrary_link_items2 PRIVATE "$<LINK_LIBRARY:feat2,base1,other>") + +add_library(LinkLibrary_link_items3 SHARED lib.c) +target_link_libraries(LinkLibrary_link_items3 PRIVATE "$<LINK_LIBRARY:feat4,base1,other>") + +add_library(LinkLibrary_link_items4 SHARED lib.c) +target_link_libraries(LinkLibrary_link_items4 PRIVATE "$<LINK_LIBRARY:feat5,base1,other>") + +add_library(base3 SHARED base.c) +target_link_libraries(base3 PRIVATE "$<LINK_LIBRARY:feat6,base1>") +add_library(LinkLibrary_mix_features1 SHARED lib.c) +target_link_libraries(LinkLibrary_mix_features1 PRIVATE "$<LINK_LIBRARY:feat2,base1,base3>") + +target_link_libraries(base3 INTERFACE "$<LINK_LIBRARY:feat2,base1>") +add_library(LinkLibrary_mix_features2 SHARED lib.c) +target_link_libraries(LinkLibrary_mix_features2 PRIVATE "$<LINK_LIBRARY:feat2,base1,base3>") + +target_link_libraries(base3 INTERFACE other1) +add_library(LinkLibrary_mix_features3 SHARED lib.c) +target_link_libraries(LinkLibrary_mix_features3 PRIVATE base2 "$<LINK_LIBRARY:feat2,base1,base3>" other2) + +# testing LINK_LIBRARY_OVERRIDE property +add_library(LinkLibrary_override_features1 SHARED lib.c) +target_link_libraries(LinkLibrary_override_features1 PRIVATE "$<LINK_LIBRARY:feat1,base1,base3>") +set_property(TARGET LinkLibrary_override_features1 PROPERTY LINK_LIBRARY_OVERRIDE "feat1,base1") + +add_library(LinkLibrary_override_features2 SHARED lib.c) +target_link_libraries(LinkLibrary_override_features2 PRIVATE "$<LINK_LIBRARY:feat1,base1,base3>") +set_property(TARGET LinkLibrary_override_features2 PROPERTY LINK_LIBRARY_OVERRIDE "feat2,base1,other1") + +add_library(LinkLibrary_override_with_default SHARED lib.c) +target_link_libraries(LinkLibrary_override_with_default PRIVATE "$<LINK_LIBRARY:feat1,base1,base3>") +set_property(TARGET LinkLibrary_override_with_default PROPERTY LINK_LIBRARY_OVERRIDE "$<$<LINK_LANGUAGE:C>:DEFAULT,base1,other1>") + +# testing LINK_LIBRARY_OVERRIDE_<LIBRARY> property +add_library(LinkLibrary_override_features3 SHARED lib.c) +target_link_libraries(LinkLibrary_override_features3 PRIVATE "$<LINK_LIBRARY:feat1,base1,base3>") +set_property(TARGET LinkLibrary_override_features3 PROPERTY LINK_LIBRARY_OVERRIDE_base1 feat1) + +add_library(LinkLibrary_override_features4 SHARED lib.c) +target_link_libraries(LinkLibrary_override_features4 PRIVATE "$<LINK_LIBRARY:feat1,base1,base3>") +set_property(TARGET LinkLibrary_override_features4 PROPERTY LINK_LIBRARY_OVERRIDE "feat3,base1,other1") +set_property(TARGET LinkLibrary_override_features4 PROPERTY LINK_LIBRARY_OVERRIDE_base1 feat2) +set_property(TARGET LinkLibrary_override_features4 PROPERTY LINK_LIBRARY_OVERRIDE_other1 feat2) diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake new file mode 100644 index 0000000..9582e11 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake @@ -0,0 +1,99 @@ + +include(RunCMake) + +cmake_policy(SET CMP0054 NEW) + +macro(run_cmake_target test subtest target) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build) + set(RunCMake_TEST_NO_CLEAN 1) + run_cmake_command(${test}-${subtest} ${CMAKE_COMMAND} --build . --target ${target} --config Release --verbose ${ARGN}) + + unset(RunCMake_TEST_BINARY_DIR) + unset(RunCMake_TEST_NO_CLEAN) +endmacro() + +# Some environments are excluded because they are not able to honor verbose mode +if ((RunCMake_GENERATOR MATCHES "Makefiles|Ninja|Xcode" + OR (RunCMake_GENERATOR MATCHES "Visual Studio" AND MSVC_VERSION GREATER_EQUAL "1600")) + AND NOT CMAKE_C_COMPILER_ID STREQUAL "Intel") + + set(RunCMake_TEST_OUTPUT_MERGE TRUE) + if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG) + set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release) + endif() + + if (CMAKE_SYSTEM_NAME STREQUAL "Windows" + OR CMAKE_SYSTEM_NAME STREQUAL "CYGWIN" + OR CMAKE_SYSTEM_NAME STREQUAL "MSYS") + set(LINK_SHARED_LIBRARY_PREFIX ${CMAKE_IMPORT_LIBRARY_PREFIX}) + set(LINK_SHARED_LIBRARY_SUFFIX ${CMAKE_IMPORT_LIBRARY_SUFFIX}) + else() + set(LINK_SHARED_LIBRARY_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX}) + set(LINK_SHARED_LIBRARY_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) + endif() + if (MINGW OR MSYS OR CYGWIN) + set(LINK_EXTERN_LIBRARY_SUFFIX "") + else() + set(LINK_EXTERN_LIBRARY_SUFFIX "${CMAKE_IMPORT_LIBRARY_SUFFIX}") + endif() + + run_cmake(LINK_LIBRARY) + + run_cmake_target(LINK_LIBRARY simple1 LinkLibrary_simple1) + run_cmake_target(LINK_LIBRARY simple2 LinkLibrary_simple2) + run_cmake_target(LINK_LIBRARY group1 LinkLibrary_group1) + run_cmake_target(LINK_LIBRARY group2 LinkLibrary_group2) + run_cmake_target(LINK_LIBRARY nested-feature1 LinkLibrary_nested_feature1) + run_cmake_target(LINK_LIBRARY nested-feature2 LinkLibrary_nested_feature2) + run_cmake_target(LINK_LIBRARY link-items1 LinkLibrary_link_items1) + run_cmake_target(LINK_LIBRARY link-items2 LinkLibrary_link_items2) + run_cmake_target(LINK_LIBRARY link-items3 LinkLibrary_link_items3) + run_cmake_target(LINK_LIBRARY link-items4 LinkLibrary_link_items4) + run_cmake_target(LINK_LIBRARY mix-features1 LinkLibrary_mix_features1) + run_cmake_target(LINK_LIBRARY mix-features2 LinkLibrary_mix_features2) + run_cmake_target(LINK_LIBRARY mix-features3 LinkLibrary_mix_features3) + + # testing target property LINK_LIBRARY_OVERRIDE + run_cmake_target(LINK_LIBRARY override-features1 LinkLibrary_override_features1) + run_cmake_target(LINK_LIBRARY override-features2 LinkLibrary_override_features2) + run_cmake_target(LINK_LIBRARY override-with-DEFAULT LinkLibrary_override_with_default) + # testing target property LINK_LIBRARY_OVERRIDE_<LIBRARY> + run_cmake_target(LINK_LIBRARY override-features3 LinkLibrary_override_features3) + run_cmake_target(LINK_LIBRARY override-features4 LinkLibrary_override_features4) + + run_cmake(imported-target) + + # tests using features as described in the documentation + if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang" + OR (CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION GREATER "1900") + OR (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_SYSTEM_NAME STREQUAL "Linux")) + run_cmake(whole_archive) + run_cmake_target(whole_archive link-exe main) + endif() + if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + run_cmake(weak_library) + run_cmake_target(weak_library link-exe main) + endif() + + unset(RunCMake_TEST_OPTIONS) + unset(RunCMake_TEST_OUTPUT_MERGE) + +endif() + +# Apple framework features +if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")) + run_cmake(apple_framework) + run_cmake_target(apple_framework framework main-framework) + run_cmake_target(apple_framework reexport_framework main-reexport_framework) + run_cmake_target(apple_framework weak_framework main-weak_framework) + + run_cmake_target(apple_framework target-framework main-target-framework) + run_cmake_target(apple_framework target-reexport_framework main-target-reexport_framework) + run_cmake_target(apple_framework target-weak_framework main-target-weak_framework) +endif() + +if (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION GREATER_EQUAL "12") + run_cmake_target(apple_framework needed_framework main-needed_framework) + + run_cmake_target(apple_framework target-needed_framework main-target-needed_framework) +endif() diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/apple_framework.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/apple_framework.cmake new file mode 100644 index 0000000..e9a93e9 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/apple_framework.cmake @@ -0,0 +1,61 @@ + +enable_language(OBJCXX) + + +# feature FRAMEWORK +add_library(foo-framework SHARED foo.mm) +target_link_libraries(foo-framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>") + +add_executable(main-framework main.mm) +target_link_libraries(main-framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" foo-framework) + + +# feature NEEDED_FRAMEWORK +add_library(foo-needed_framework SHARED foo.mm) +target_link_libraries(foo-needed_framework PRIVATE "$<LINK_LIBRARY:NEEDED_FRAMEWORK,Foundation>") + +add_executable(main-needed_framework main.mm) +target_link_libraries(main-needed_framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" foo-needed_framework) + + +# feature REEXPORT_FRAMEWORK +add_library(foo-reexport_framework SHARED foo.mm) +target_link_libraries(foo-reexport_framework PRIVATE "$<LINK_LIBRARY:REEXPORT_FRAMEWORK,Foundation>") + +add_executable(main-reexport_framework main.mm) +target_link_libraries(main-reexport_framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" foo-reexport_framework) + + +# feature WEAK_FRAMEWORK +add_library(foo-weak_framework SHARED foo.mm) +target_link_libraries(foo-weak_framework PRIVATE "$<LINK_LIBRARY:WEAK_FRAMEWORK,Foundation>") + +add_executable(main-weak_framework main.mm) +target_link_libraries(main-weak_framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" foo-weak_framework) + + +## +## Consumption of target specified as FRAMEWORK +add_library(target-framework SHARED foo.mm) +set_target_properties(target-framework PROPERTIES FRAMEWORK TRUE) +target_link_libraries(target-framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>") + + +# feature FRAMEWORK +add_executable(main-target-framework main.mm) +target_link_libraries(main-target-framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" "$<LINK_LIBRARY:FRAMEWORK,target-framework>") + + +# feature NEEDED_FRAMEWORK +add_executable(main-target-needed_framework main.mm) +target_link_libraries(main-target-needed_framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" "$<LINK_LIBRARY:NEEDED_FRAMEWORK,target-framework>") + + +# feature REEXPORT_FRAMEWORK +add_executable(main-target-reexport_framework main.mm) +target_link_libraries(main-target-reexport_framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" "$<LINK_LIBRARY:REEXPORT_FRAMEWORK,target-framework>") + + +# feature WEAK_FRAMEWORK +add_executable(main-target-weak_framework main.mm) +target_link_libraries(main-target-weak_framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" "$<LINK_LIBRARY:REEXPORT_FRAMEWORK,target-framework>") diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/base.c b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/base.c new file mode 100644 index 0000000..a5075d4 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/base.c @@ -0,0 +1,9 @@ + +#if !defined(STATIC_BASE) +# if defined(_WIN32) +__declspec(dllexport) +# endif +#endif + void base() +{ +} diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.h b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.h new file mode 100644 index 0000000..b3fb084 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.h @@ -0,0 +1,9 @@ +#import <Foundation/Foundation.h> + +@interface Foo : NSObject { + NSNumber* age; +} + +@property (nonatomic, retain) NSNumber* age; + +@end diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.mm b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.mm new file mode 100644 index 0000000..2d452a8 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.mm @@ -0,0 +1,7 @@ +#import "foo.h" + +@implementation Foo + +@synthesize age; + +@end diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target-stdout.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target-stdout.txt new file mode 100644 index 0000000..981376a --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target-stdout.txt @@ -0,0 +1,18 @@ +CMake Warning \(dev\) at imported-target.cmake:[0-9]+ \(add_library\): + The 'IMPORTED' target 'NS::lib2' uses the generator-expression + '\$<LINK_LIBRARY>' with the feature 'whole_archive', which is undefined or + unsupported. + + Did you miss to define it by setting variables + "CMAKE_C_LINK_LIBRARY_USING_whole_archive" and + "CMAKE_C_LINK_LIBRARY_USING_whole_archive_SUPPORTED"\? +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Error at imported-target.cmake:[0-9]+ \(add_library\): + Feature 'whole_archive', specified through generator-expression + '\$<LINK_LIBRARY>' to link target 'lib', is not supported for the 'C' link + language. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target.cmake new file mode 100644 index 0000000..9283054 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/imported-target.cmake @@ -0,0 +1,18 @@ + +enable_language(C) + +# Create imported target NS::lib +add_library(NS::lib STATIC IMPORTED) + +# Create imported target NS::lib2 +add_library(NS::lib2 SHARED IMPORTED) + +set_target_properties(NS::lib2 PROPERTIES + IMPORTED_LOCATION "/path/to/lib" + IMPORTED_IMPLIB "/path/to/import.lib" + INTERFACE_LINK_LIBRARIES "$<LINK_LIBRARY:whole_archive,NS::lib>" +) + + +add_library(lib SHARED lib.c) +target_link_libraries(lib PRIVATE NS::lib2) diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/lib.c b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/lib.c new file mode 100644 index 0000000..35ab367 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/lib.c @@ -0,0 +1,15 @@ + +#if !defined(STATIC_BASE) +# if defined(_WIN32) +__declspec(dllimport) +# endif +#endif + void base(); + +#if defined(_WIN32) +__declspec(dllexport) +#endif + void lib() +{ + base(); +} diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.c b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.c new file mode 100644 index 0000000..601bd96 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.c @@ -0,0 +1,18 @@ + +#if defined(_WIN32) +__declspec(dllimport) +#endif + void lib(); + +#if defined(_WIN32) +__declspec(dllimport) +#endif + void unref(); + +int main() +{ + lib(); + unref(); + + return 0; +} diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.mm b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.mm new file mode 100644 index 0000000..7c85551 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.mm @@ -0,0 +1,14 @@ +#import <Foundation/Foundation.h> +#import "foo.h" +#include <iostream> + +int main(int argc, char **argv) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + Foo *theFoo = [[Foo alloc] init]; + theFoo.age = [NSNumber numberWithInt:argc]; + NSLog(@"%d\n",[theFoo.age intValue]); + std::cout << [theFoo.age intValue] << std::endl; + [pool release]; + return 0; +} diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/unref.c b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/unref.c new file mode 100644 index 0000000..37c3206 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/unref.c @@ -0,0 +1,8 @@ + + +#if defined(_WIN32) +__declspec(dllexport) +#endif + void unref() +{ +} diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/weak_library.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/weak_library.cmake new file mode 100644 index 0000000..45b4f66 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/weak_library.cmake @@ -0,0 +1,20 @@ + +enable_language(C) + +if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + set(CMAKE_LINK_LIBRARY_USING_weak_library "PATH{-weak_library <LIBRARY>}NAME{LINKER:-weak-l<LIB_ITEM>}") + set(CMAKE_LINK_LIBRARY_USING_weak_library_SUPPORTED TRUE) +else() + # feature not yet supported for the other environments + set(CMAKE_LINK_LIBRARY_USING_whole_library_SUPPORTED FALSE) +endif() + +add_library(lib SHARED base.c lib.c unref.c) +set_property(TARGET lib PROPERTY OUTPUT_NAME base) + +add_executable(main main.c) +target_link_libraries(main PRIVATE "$<LINK_LIBRARY:weak_library,lib>") + +add_executable(main2 main.c) +target_link_directories(main2 PRIVATE "$<TARGET_FILE_DIR:lib>") +target_link_libraries(main2 PRIVATE "$<LINK_LIBRARY:weak_library,base>") diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/whole_archive.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/whole_archive.cmake new file mode 100644 index 0000000..93082a4 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/whole_archive.cmake @@ -0,0 +1,34 @@ + +enable_language(C) + +set(CMAKE_C_LINK_LIBRARY_USING_whole_archive_SUPPORTED TRUE) +if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + set(CMAKE_C_LINK_LIBRARY_USING_whole_archive "-force_load <LIB_ITEM>") +elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + execute_process(COMMAND "${CMAKE_LINKER}" --help + OUTPUT_VARIABLE linker_help + ERROR_VARIABLE linker_help) + if(linker_help MATCHES "--push-state" AND linker_help MATCHES "--pop-state") + set(CMAKE_C_LINK_LIBRARY_USING_whole_archive "LINKER:--push-state,--whole-archive" + "<LINK_ITEM>" + "LINKER:--pop-state") + else() + set(CMAKE_C_LINK_LIBRARY_USING_whole_archive "LINKER:--whole-archive" + "<LINK_ITEM>" + "LINKER:--no-whole-archive") + endif() +elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_C_LINK_LIBRARY_USING_whole_archive "/WHOLEARCHIVE:<LIBRARY>") +else() + # feature not yet supported for the other environments + set(CMAKE_C_LINK_LIBRARY_USING_whole_archive_SUPPORTED FALSE) +endif() + +add_library(base STATIC base.c unref.c) +target_compile_definitions(base PUBLIC STATIC_BASE) + +add_library(lib SHARED lib.c) +target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:whole_archive,base>") + +add_executable(main main.c) +target_link_libraries(main PRIVATE lib) diff --git a/Tests/TryCompile/CMakeLists.txt b/Tests/TryCompile/CMakeLists.txt index b1b9d57..594f37a 100644 --- a/Tests/TryCompile/CMakeLists.txt +++ b/Tests/TryCompile/CMakeLists.txt @@ -32,7 +32,7 @@ endmacro() # try to compile a file that should compile # also check that COPY_FILE works try_compile(SHOULD_PASS - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${TryCompile_SOURCE_DIR}/pass.c OUTPUT_VARIABLE TRY_OUT COPY_FILE ${TryCompile_BINARY_DIR}/CopyOfPass @@ -51,7 +51,7 @@ endif() # also check that COPY_FILE_ERROR works file(WRITE ${TryCompile_BINARY_DIR}/invalid "") try_compile(SHOULD_PASS - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${TryCompile_SOURCE_DIR}/pass.c OUTPUT_VARIABLE TRY_OUT COPY_FILE ${TryCompile_BINARY_DIR}/invalid/path @@ -66,7 +66,7 @@ endif() # try to compile a file that should not compile try_compile(SHOULD_FAIL - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${TryCompile_SOURCE_DIR}/fail.c OUTPUT_VARIABLE TRY_OUT) if(SHOULD_FAIL) @@ -75,7 +75,7 @@ endif() # try to compile a file that should compile try_compile(SHOULD_PASS - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${TryCompile_SOURCE_DIR}/pass.c OUTPUT_VARIABLE TRY_OUT) if(NOT SHOULD_PASS) @@ -84,7 +84,7 @@ endif() # try to compile a file that should not compile try_compile(SHOULD_FAIL - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${TryCompile_SOURCE_DIR}/fail.c OUTPUT_VARIABLE TRY_OUT) if(SHOULD_FAIL) @@ -93,7 +93,7 @@ endif() # try to compile two files that should compile try_compile(SHOULD_PASS - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} SOURCES ${TryCompile_SOURCE_DIR}/pass2a.c ${TryCompile_SOURCE_DIR}/pass2b.cxx OUTPUT_VARIABLE TRY_OUT) if(NOT SHOULD_PASS) @@ -102,7 +102,7 @@ endif() # try to compile two files that should not compile try_compile(SHOULD_FAIL - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} SOURCES ${TryCompile_SOURCE_DIR}/fail2a.c ${TryCompile_SOURCE_DIR}/fail2b.c OUTPUT_VARIABLE TRY_OUT) if(SHOULD_FAIL) @@ -117,7 +117,7 @@ else() string(APPEND CMAKE_C_FLAGS " \"-DTESTDEF\"") endif() try_compile(SHOULD_PASS - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${TryCompile_SOURCE_DIR}/testdef.c OUTPUT_VARIABLE TRY_OUT) if(NOT SHOULD_PASS) @@ -135,7 +135,7 @@ else() message("Test failed") endif() try_compile(CMAKE_ANSI_FOR_SCOPE - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${CMAKE_ROOT}/Modules/TestForAnsiForScope.cxx OUTPUT_VARIABLE OUT) if (CMAKE_ANSI_FOR_SCOPE) message("Compiler supports ansi for") @@ -144,7 +144,7 @@ else() endif() try_compile(CMAKE_ANSI_FOR_SCOPE - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${CMAKE_ROOT}/Modules/TestForAnsiForScope.cxx OUTPUT_VARIABLE OUT) if (CMAKE_ANSI_FOR_SCOPE) message("Compiler supports ansi for") @@ -169,7 +169,7 @@ try_compile(TEST_INNER TEST_ASSERT(TEST_INNER "try_compile project mode failed:\n${output}") try_compile(COMPILE_DEFINITIONS_LIST_EXPANDED - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${TryCompile_SOURCE_DIR}/check_a_b.c OUTPUT_VARIABLE output COMPILE_DEFINITIONS "-DDEF_A;-DDEF_B" @@ -182,7 +182,7 @@ else() endif() try_compile(SHOULD_FAIL_DUE_TO_BAD_SOURCE - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${TryCompile_SOURCE_DIR}/pass.c OUTPUT_VARIABLE output COMPILE_DEFINITIONS "bad#source.c" @@ -207,7 +207,7 @@ add_executable(TryCompile pass.c) # also check that OUTPUT_VARIABLE contains both the compile output # and the run output try_run(SHOULD_RUN SHOULD_COMPILE - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${TryCompile_SOURCE_DIR}/exit_success.c OUTPUT_VARIABLE TRY_OUT) if(NOT SHOULD_COMPILE) @@ -226,7 +226,7 @@ if(NOT "${TRY_OUT}" MATCHES "hello world") endif() try_run(ARG_TEST_RUN ARG_TEST_COMPILE - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${TryCompile_SOURCE_DIR}/expect_arg.c OUTPUT_VARIABLE TRY_OUT ARGS arg1 arg2) @@ -239,7 +239,7 @@ endif() # try to run a file that should compile and run, but return an error try_run(SHOULD_EXIT_WITH_ERROR SHOULD_COMPILE - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${TryCompile_SOURCE_DIR}/exit_with_error.c COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT RUN_OUTPUT_VARIABLE RUN_OUTPUT) @@ -385,7 +385,7 @@ if (APPLE) # try to compile a file that should compile try_compile(SHOULD_PASS - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${TryCompile_SOURCE_DIR}/pass.m OUTPUT_VARIABLE TRY_OUT) if(NOT SHOULD_PASS) @@ -394,7 +394,7 @@ if (APPLE) # try to compile a file that should not compile try_compile(SHOULD_FAIL - ${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompile_BINARY_DIR} ${TryCompile_SOURCE_DIR}/fail.m OUTPUT_VARIABLE TRY_OUT) if(SHOULD_FAIL) diff --git a/Tests/TryCompile/Inner/CMakeLists.txt b/Tests/TryCompile/Inner/CMakeLists.txt index d8c22d0..9f89af2 100644 --- a/Tests/TryCompile/Inner/CMakeLists.txt +++ b/Tests/TryCompile/Inner/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8.12) project(TryCompileInner C) try_compile(SHOULD_PASS - ${TryCompileInner_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp + ${TryCompileInner_BINARY_DIR} ${TryCompileInner_SOURCE_DIR}/../pass.c OUTPUT_VARIABLE TRY_OUT ) diff --git a/Tests/VSWinStorePhone/CMakeLists.txt b/Tests/VSWinStorePhone/CMakeLists.txt index edd4330..2cb80fa 100644 --- a/Tests/VSWinStorePhone/CMakeLists.txt +++ b/Tests/VSWinStorePhone/CMakeLists.txt @@ -63,7 +63,8 @@ set(VERTEXSHADER_FILES Direct3DApp1/SimpleVertexShader.hlsl ) -set(CONTENT_FILES ${PIXELSHADER_FILES} ${VERTEXSHADER_FILES}) + set(COPY_TO_OUTPUT_FILES Direct3DApp1/Simple.manifest) + set(CONTENT_FILES ${PIXELSHADER_FILES} ${VERTEXSHADER_FILES} ${COPY_TO_OUTPUT_FILES}) if (WINDOWS_PHONE8) set(CONTENT_FILES ${CONTENT_FILES} @@ -108,6 +109,7 @@ set(RESOURCE_FILES ${CONTENT_FILES} ${DEBUG_CONTENT_FILES} ${RELEASE_CONTENT_FILES} ${ASSET_FILES} ${STRING_FILES} Direct3DApp1/Direct3DApp1_TemporaryKey.pfx) +set_property(SOURCE ${COPY_TO_OUTPUT_FILES} PROPERTY VS_COPY_TO_OUT_DIR "PreserveNewest") set_property(SOURCE ${CONTENT_FILES} PROPERTY VS_DEPLOYMENT_CONTENT 1) set_property(SOURCE ${ASSET_FILES} PROPERTY VS_DEPLOYMENT_CONTENT 1) set_property(SOURCE ${ASSET_FILES} PROPERTY VS_DEPLOYMENT_LOCATION "Assets") diff --git a/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.cpp b/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.cpp index 595f553..d287857 100644 --- a/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.cpp +++ b/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.cpp @@ -17,6 +17,13 @@ CubeRenderer::CubeRenderer() // Create a new WinRT object to validate that we can link properly Batman ^ hero = ref new Batman(); hero->savePeople(); + + // Test that .manifest files can be bundled with app + DX::ReadDataAsync("Direct3DApp1\\Simple.manifest") + .then([this](Platform::Array<byte> ^ fileData) { + std::string manifestContent(fileData->begin(), fileData->end()); + assert(manifestContent.find("hello") == 0); + }); } void CubeRenderer::CreateDeviceResources() diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Simple.manifest b/Tests/VSWinStorePhone/Direct3DApp1/Simple.manifest new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/Tests/VSWinStorePhone/Direct3DApp1/Simple.manifest @@ -0,0 +1 @@ +hello diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt index 72cfc05..d32947b 100644 --- a/Utilities/Doxygen/CMakeLists.txt +++ b/Utilities/Doxygen/CMakeLists.txt @@ -3,7 +3,7 @@ if(NOT CMake_SOURCE_DIR) set(CMakeDeveloperReference_STANDALONE 1) - cmake_minimum_required(VERSION 3.1...3.21 FATAL_ERROR) + cmake_minimum_required(VERSION 3.1...3.22 FATAL_ERROR) get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH) get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH) include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake) diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt index 073e5ff..b8b244d 100644 --- a/Utilities/Sphinx/CMakeLists.txt +++ b/Utilities/Sphinx/CMakeLists.txt @@ -3,7 +3,7 @@ if(NOT CMake_SOURCE_DIR) set(CMakeHelp_STANDALONE 1) - cmake_minimum_required(VERSION 3.1...3.21 FATAL_ERROR) + cmake_minimum_required(VERSION 3.1...3.22 FATAL_ERROR) get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH) get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH) include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake) @@ -442,6 +442,7 @@ CMAKE_CXX_SOURCES="\ cmGccDepfileLexerHelper \ cmGccDepfileReader \ cmReturnCommand \ + cmPlaceholderExpander \ cmRulePlaceholderExpander \ cmRuntimeDependencyArchive \ cmScriptGenerator \ |