diff options
75 files changed, 1179 insertions, 689 deletions
diff --git a/Help/command/DEVICE_LINK_OPTIONS.txt b/Help/command/DEVICE_LINK_OPTIONS.txt index 012e9b1..3f0226f 100644 --- a/Help/command/DEVICE_LINK_OPTIONS.txt +++ b/Help/command/DEVICE_LINK_OPTIONS.txt @@ -1,9 +1,10 @@ When a device link step is involved, which is controlled by :prop_tgt:`CUDA_SEPARABLE_COMPILATION` and -:prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` properties, the raw options will be -delivered to the host and device link steps (wrapped in ``-Xcompiler`` or -equivalent for device link). Options wrapped with ``$<DEVICE_LINK:...>`` +:prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` properties and policy :policy:`CMP0105`, +the raw options will be delivered to the host and device link steps (wrapped in +``-Xcompiler`` or equivalent for device link). Options wrapped with +``$<DEVICE_LINK:...>`` :manual:`generator expression <cmake-generator-expressions(7)>` will be used only for the device link step. Options wrapped with ``$<HOST_LINK:...>`` :manual:`generator expression <cmake-generator-expressions(7)>` will be used diff --git a/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt index c911625..a47d5e0 100644 --- a/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt @@ -57,7 +57,11 @@ set_property(TARGET MathFunctions PROPERTY VERSION "1.0.0") set_property(TARGET MathFunctions PROPERTY SOVERSION "1") # install rules -install(TARGETS MathFunctions tutorial_compiler_flags +set(installable_libs MathFunctions tutorial_compiler_flags) +if(TARGET SqrtLibrary) + list(APPEND installable_libs SqrtLibrary) +endif() +install(TARGETS ${installable_libs} DESTINATION lib EXPORT MathFunctionsTargets) install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt index e0c0621..0bfe20c 100644 --- a/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt @@ -47,5 +47,9 @@ endif() target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH") # install rules -install(TARGETS MathFunctions DESTINATION lib) +set(installable_libs MathFunctions) +if(TARGET SqrtLibrary) + list(APPEND installable_libs SqrtLibrary) +endif() +install(TARGETS ${installable_libs} DESTINATION lib) install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt index 32f5e08..0d287ca 100644 --- a/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt @@ -51,5 +51,9 @@ target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags) target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH") # install rules -install(TARGETS MathFunctions DESTINATION lib) +set(installable_libs MathFunctions tutorial_compiler_flags) +if(TARGET SqrtLibrary) + list(APPEND installable_libs SqrtLibrary) +endif() +install(TARGETS ${installable_libs} DESTINATION lib) install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt index 720ee64..ea3861c 100644 --- a/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt @@ -53,7 +53,11 @@ target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags) target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH") # install rules -install(TARGETS MathFunctions tutorial_compiler_flags +set(installable_libs MathFunctions tutorial_compiler_flags) +if(TARGET SqrtLibrary) + list(APPEND installable_libs SqrtLibrary) +endif() +install(TARGETS ${installable_libs} DESTINATION lib EXPORT MathFunctionsTargets) install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/index.rst b/Help/guide/tutorial/index.rst index 6e26de9..e7ea290 100644 --- a/Help/guide/tutorial/index.rst +++ b/Help/guide/tutorial/index.rst @@ -675,9 +675,9 @@ The first step is to update the starting section of the top-level Now that we have made MathFunctions always be used, we will need to update the logic of that library. So, in ``MathFunctions/CMakeLists.txt`` we need to -create a SqrtLibrary that will conditionally be built when ``USE_MYMATH`` is -enabled. Now, since this is a tutorial, we are going to explicitly require -that SqrtLibrary is built statically. +create a SqrtLibrary that will conditionally be built and installed when +``USE_MYMATH`` is enabled. Now, since this is a tutorial, we are going to +explicitly require that SqrtLibrary is built statically. The end result is that ``MathFunctions/CMakeLists.txt`` should look like: @@ -703,7 +703,7 @@ Finally, update ``MathFunctions/MathFunctions.h`` to use dll export defines: .. literalinclude:: Step10/MathFunctions/MathFunctions.h :language: c++ -At this point, if you build everything, you will notice that linking fails +At this point, if you build everything, you may notice that linking fails as we are combining a static library without position independent code with a library that has position independent code. The solution to this is to explicitly set the :prop_tgt:`POSITION_INDEPENDENT_CODE` target property of diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index 9e411a4..124da44 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -365,8 +365,9 @@ Variable Queries ``$<DEVICE_LINK:list>`` Returns the list if it is the device link step, an empty list otherwise. The device link step is controlled by :prop_tgt:`CUDA_SEPARABLE_COMPILATION` - and :prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` properties. This expression can - only be used to specify link options. + and :prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` properties and + policy :policy:`CMP0105`. This expression can only be used to specify link + options. ``$<HOST_LINK:list>`` Returns the list if it is the normal link step, an empty list otherwise. diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 7f7ed50..30b2a05 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -128,7 +128,6 @@ Properties on Targets /prop_tgt/ARCHIVE_OUTPUT_DIRECTORY /prop_tgt/ARCHIVE_OUTPUT_NAME_CONFIG /prop_tgt/ARCHIVE_OUTPUT_NAME - /prop_tgt/PCH_WARN_INVALID /prop_tgt/AUTOGEN_BUILD_DIR /prop_tgt/AUTOGEN_ORIGIN_DEPENDS /prop_tgt/AUTOGEN_PARALLEL @@ -312,6 +311,7 @@ Properties on Targets /prop_tgt/OSX_ARCHITECTURES /prop_tgt/OUTPUT_NAME_CONFIG /prop_tgt/OUTPUT_NAME + /prop_tgt/PCH_WARN_INVALID /prop_tgt/PDB_NAME_CONFIG /prop_tgt/PDB_NAME /prop_tgt/PDB_OUTPUT_DIRECTORY_CONFIG diff --git a/Help/prop_sf/VS_SETTINGS.rst b/Help/prop_sf/VS_SETTINGS.rst index 0719406..50034fb 100644 --- a/Help/prop_sf/VS_SETTINGS.rst +++ b/Help/prop_sf/VS_SETTINGS.rst @@ -15,4 +15,4 @@ For example: will set ``Key`` to ``Value`` and ``Key2`` to ``Value2`` on the ``file.hlsl`` item as metadata. -Generator expressions are supported. +:manual:`Generator expressions <cmake-generator-expressions(7)>` are supported. diff --git a/Help/prop_tgt/FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst b/Help/prop_tgt/FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst index 2b20bf9..5d0fc3d 100644 --- a/Help/prop_tgt/FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst +++ b/Help/prop_tgt/FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst @@ -1,24 +1,25 @@ FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG> --------------------------------------- -Postfix to append to the framework file name for configuration <CONFIG>, +Postfix to append to the framework file name for configuration ``<CONFIG>``, when using a multi-config generator (like Xcode and Ninja Multi-Config). -When building with configuration <CONFIG> the value of this property +When building with configuration ``<CONFIG>`` the value of this property is appended to the framework file name built on disk. -For example given a framework called ``my_fw``, a value of ``_debug`` -for the :prop_tgt:`FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>` property, and -``Debug;Release`` in `CMAKE_CONFIGURATION_TYPES`, the following relevant -files would be created for the ``Debug`` and ``Release`` configurations: +For example, given a framework called ``my_fw``, a value of ``_debug`` +for the ``FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>`` property, and +``Debug;Release`` in :variable:`CMAKE_CONFIGURATION_TYPES`, the following +relevant files would be created for the ``Debug`` and ``Release`` +configurations: -- Release/my_fw.framework/my_fw -- Release/my_fw.framework/Versions/A/my_fw -- Debug/my_fw.framework/my_fw_debug -- Debug/my_fw.framework/Versions/A/my_fw_debug +- ``Release/my_fw.framework/my_fw`` +- ``Release/my_fw.framework/Versions/A/my_fw`` +- ``Debug/my_fw.framework/my_fw_debug`` +- ``Debug/my_fw.framework/Versions/A/my_fw_debug`` For framework targets, this property is initialized by the value of the -variable :variable:`CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>` if it +:variable:`CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>` variable if it is set when a target is created. This property is ignored for non-framework targets, and when using single diff --git a/Help/prop_tgt/PCH_WARN_INVALID.rst b/Help/prop_tgt/PCH_WARN_INVALID.rst index 36ec348..96e1abd 100644 --- a/Help/prop_tgt/PCH_WARN_INVALID.rst +++ b/Help/prop_tgt/PCH_WARN_INVALID.rst @@ -2,7 +2,9 @@ PCH_WARN_INVALID ---------------- When this property is set to true, the precompile header compiler options -will contain a compiler flag wich should warn about invalid precompiled +will contain a compiler flag which should warn about invalid precompiled headers e.g. ``-Winvalid-pch`` for GNU compiler. -The defalut value is ``ON``. +This property is initialized by the value of the +:variable:`CMAKE_PCH_WARN_INVALID` variable if it is set when a target is +created. If that variable is not set, the property defaults to ``ON``. diff --git a/Help/prop_tgt/VS_SOLUTION_DEPLOY.rst b/Help/prop_tgt/VS_SOLUTION_DEPLOY.rst index 7906d75..eef848f 100644 --- a/Help/prop_tgt/VS_SOLUTION_DEPLOY.rst +++ b/Help/prop_tgt/VS_SOLUTION_DEPLOY.rst @@ -4,24 +4,22 @@ VS_SOLUTION_DEPLOY Specify that the target should be marked for deployment when not targeting Windows CE, Windows Phone or a Windows Store application. -If the target platform doesn't support deployment, this property won't have any effect. +If the target platform doesn't support deployment, this property won't have +any effect. -Generator expressions are supported. +:manual:`Generator expressions <cmake-generator-expressions(7)>` are supported. -Example 1 -^^^^^^^^^ +Examples +^^^^^^^^ -This shows setting the variable for the target foo. +Always deploy target ``foo``: .. code-block:: cmake add_executable(foo SHARED foo.cpp) set_property(TARGET foo PROPERTY VS_SOLUTION_DEPLOY ON) -Example 2 -^^^^^^^^^ - -This shows setting the variable for the Release configuration only. +Deploy target ``foo`` for all configurations except ``Release``: .. code-block:: cmake diff --git a/Help/prop_tgt/VS_SOURCE_SETTINGS_tool.rst b/Help/prop_tgt/VS_SOURCE_SETTINGS_tool.rst index f706888..738a912 100644 --- a/Help/prop_tgt/VS_SOURCE_SETTINGS_tool.rst +++ b/Help/prop_tgt/VS_SOURCE_SETTINGS_tool.rst @@ -16,4 +16,4 @@ For example: will set ``Key`` to ``Value`` and ``Key2`` to ``Value2`` for all non-built files that use ``FXCompile``. -Generator expressions are supported. +:manual:`Generator expressions <cmake-generator-expressions(7)>` are supported. diff --git a/Help/release/3.18.rst b/Help/release/3.18.rst index 072f9aa..c98b12a 100644 --- a/Help/release/3.18.rst +++ b/Help/release/3.18.rst @@ -117,6 +117,9 @@ Properties * The :prop_sf:`OBJECT_OUTPUTS` source file property now supports :manual:`generator expressions <cmake-generator-expressions(7)>`. +* The :prop_tgt:`PCH_WARN_INVALID` target property was added to allow the + removal of the precompiled header invalid warning. + * The :prop_tgt:`UNITY_BUILD_MODE` target property was added to tell generators which algorithm to use for grouping included source files. @@ -157,6 +160,14 @@ Modules * The :module:`FindBLAS` module now provides an imported target. +* The :module:`FindCUDAToolkit` module: + + * gained the variable + ``CUDAToolkit_LIBRARY_ROOT``, which is the directory containing the + ``nvvm`` directory and ``version.txt``. + + * uses toolkit and library root found during ``CUDA`` compiler detection. + * The :module:`FindLAPACK` module now provides an imported target. * The :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython` @@ -195,14 +206,6 @@ Modules .. _`SWIG-Fortran`: https://github.com/swig-fortran/swig -* The :module:`FindCUDAToolkit` module: - - * gained the variable - ``CUDAToolkit_LIBRARY_ROOT``, which is the directory containing the - ``nvvm`` directory and ``version.txt``. - - * uses toolkit and library root found during ``CUDA`` compiler detection. - Generator Expressions --------------------- @@ -243,9 +246,9 @@ CPack installer is DPI-aware. * The :cpack_gen:`CPack RPM Generator` gained - :variable:`CPACK_RPM_PRE_TRANS_SCRIPT_FILE` + :variable:`CPACK_RPM_PRE_TRANS_SCRIPT_FILE` and :variable:`CPACK_RPM_POST_TRANS_SCRIPT_FILE` - variables to specify pre- and post-trans scripts. + variables to specify pre- and post-transaction scripts. Other ----- diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake index e12da45..692ce20 100644 --- a/Modules/CMakeDetermineCUDACompiler.cmake +++ b/Modules/CMakeDetermineCUDACompiler.cmake @@ -51,146 +51,139 @@ endif() if(NOT CMAKE_CUDA_COMPILER_ID_RUN) set(CMAKE_CUDA_COMPILER_ID_RUN 1) - # Try to identify the compiler. - set(CMAKE_CUDA_COMPILER_ID) - set(CMAKE_CUDA_PLATFORM_ID) - file(READ ${CMAKE_ROOT}/Modules/CMakePlatformId.h.in - CMAKE_CUDA_COMPILER_ID_PLATFORM_CONTENT) - - list(APPEND CMAKE_CUDA_COMPILER_ID_VENDORS NVIDIA Clang) - set(CMAKE_CUDA_COMPILER_ID_VENDOR_REGEX_NVIDIA "nvcc: NVIDIA \\(R\\) Cuda compiler driver") - set(CMAKE_CUDA_COMPILER_ID_VENDOR_REGEX_Clang "(clang version)") - - set(CMAKE_CXX_COMPILER_ID_TOOL_MATCH_REGEX "\nLd[^\n]*(\n[ \t]+[^\n]*)*\n[ \t]+([^ \t\r\n]+)[^\r\n]*-o[^\r\n]*CompilerIdCUDA/(\\./)?(CompilerIdCUDA.xctest/)?CompilerIdCUDA[ \t\n\\\"]") - set(CMAKE_CXX_COMPILER_ID_TOOL_MATCH_INDEX 2) - set(CMAKE_CUDA_COMPILER_ID_FLAGS_ALWAYS "-v") - - # We determine the vendor to help with find the toolkit and use the right flags for detection right away. include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake) - CMAKE_DETERMINE_COMPILER_ID_VENDOR(CUDA "--version") - - # Find the CUDA toolkit. We store the CMAKE_CUDA_COMPILER_TOOLKIT_ROOT and CMAKE_CUDA_COMPILER_LIBRARY_ROOT - # in CMakeCUDACompiler.cmake, so FindCUDAToolkit can avoid searching on future runs and the toolkit stays the same. - # This is very similar to FindCUDAToolkit, but somewhat simplified since we can issue fatal errors - # if we fail to find things we need and we don't need to account for searching the libraries. - # For NVCC we can easily deduce the SDK binary directory from the compiler path. - if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") - get_filename_component(_CUDA_BIN_DIR "${CMAKE_CUDA_COMPILER}" DIRECTORY) - find_program(CUDAToolkit_NVCC_EXECUTABLE - NAMES nvcc nvcc.exe - PATHS ${_CUDA_BIN_DIR} - NO_DEFAULT_PATH - ) - unset(_CUDA_BIN_DIR) - endif() + if(${CMAKE_GENERATOR} MATCHES "Visual Studio") + # We will not know CMAKE_CUDA_COMPILER until the main compiler id step + # below extracts it, but we do know that the compiler id will be NVIDIA. + set(CMAKE_CUDA_COMPILER_ID "NVIDIA") + else() + # We determine the vendor to help with find the toolkit and use the right flags for detection right away. + # The main compiler identification is still needed below to extract other information. + list(APPEND CMAKE_CUDA_COMPILER_ID_VENDORS NVIDIA Clang) + set(CMAKE_CUDA_COMPILER_ID_VENDOR_REGEX_NVIDIA "nvcc: NVIDIA \\(R\\) Cuda compiler driver") + set(CMAKE_CUDA_COMPILER_ID_VENDOR_REGEX_Clang "(clang version)") + CMAKE_DETERMINE_COMPILER_ID_VENDOR(CUDA "--version") + + # Find the CUDA toolkit. We store the CMAKE_CUDA_COMPILER_TOOLKIT_ROOT and CMAKE_CUDA_COMPILER_LIBRARY_ROOT + # in CMakeCUDACompiler.cmake, so FindCUDAToolkit can avoid searching on future runs and the toolkit stays the same. + # This is very similar to FindCUDAToolkit, but somewhat simplified since we can issue fatal errors + # if we fail to find things we need and we don't need to account for searching the libraries. + + # For NVCC we can easily deduce the SDK binary directory from the compiler path. + if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") + set(_CUDA_NVCC_EXECUTABLE "${CMAKE_CUDA_COMPILER}") + else() + # Search using CUDAToolkit_ROOT and then CUDA_PATH for equivalence with FindCUDAToolkit. + # In FindCUDAToolkit CUDAToolkit_ROOT is searched automatically due to being in a find_package(). + # First we search candidate non-default paths to give them priority. + find_program(_CUDA_NVCC_EXECUTABLE + NAMES nvcc nvcc.exe + PATHS ${CUDAToolkit_ROOT} + ENV CUDAToolkit_ROOT + ENV CUDA_PATH + PATH_SUFFIXES bin + NO_DEFAULT_PATH + ) + + # If we didn't find NVCC, then try the default paths. + find_program(_CUDA_NVCC_EXECUTABLE + NAMES nvcc nvcc.exe + PATH_SUFFIXES bin + ) + + # If the user specified CUDAToolkit_ROOT but nvcc could not be found, this is an error. + if(NOT _CUDA_NVCC_EXECUTABLE AND (DEFINED CUDAToolkit_ROOT OR DEFINED ENV{CUDAToolkit_ROOT})) + set(fail_base "Could not find nvcc executable in path specified by") + + if(DEFINED CUDAToolkit_ROOT) + message(FATAL_ERROR "${fail_base} CUDAToolkit_ROOT=${CUDAToolkit_ROOT}") + elseif(DEFINED ENV{CUDAToolkit_ROOT}) + message(FATAL_ERROR "${fail_base} environment variable CUDAToolkit_ROOT=$ENV{CUDAToolkit_ROOT}") + endif() + endif() - # Search using CUDAToolkit_ROOT and then CUDA_PATH for equivalence with FindCUDAToolkit. - # In FindCUDAToolkit CUDAToolkit_ROOT is searched automatically due to being in a find_package(). - # First we search candidate non-default paths to give them priority. - find_program(_CUDA_NVCC_EXECUTABLE - NAMES nvcc nvcc.exe - PATHS ${CUDAToolkit_ROOT} - ENV CUDAToolkit_ROOT - ENV CUDA_PATH - PATH_SUFFIXES bin - NO_DEFAULT_PATH - ) + # CUDAToolkit_ROOT cmake/env variable not specified, try platform defaults. + # + # - Linux: /usr/local/cuda-X.Y + # - macOS: /Developer/NVIDIA/CUDA-X.Y + # - Windows: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vX.Y + # + # We will also search the default symlink location /usr/local/cuda first since + # if CUDAToolkit_ROOT is not specified, it is assumed that the symlinked + # directory is the desired location. + if(NOT _CUDA_NVCC_EXECUTABLE) + if(UNIX) + if(NOT APPLE) + set(platform_base "/usr/local/cuda-") + else() + set(platform_base "/Developer/NVIDIA/CUDA-") + endif() + else() + set(platform_base "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v") + endif() - # If we didn't find NVCC, then try the default paths. - find_program(_CUDA_NVCC_EXECUTABLE - NAMES nvcc nvcc.exe - PATH_SUFFIXES bin - ) + # Build out a descending list of possible cuda installations, e.g. + file(GLOB possible_paths "${platform_base}*") + # Iterate the glob results and create a descending list. + set(versions) + foreach(p ${possible_paths}) + # Extract version number from end of string + string(REGEX MATCH "[0-9][0-9]?\\.[0-9]$" p_version ${p}) + if(IS_DIRECTORY ${p} AND p_version) + list(APPEND versions ${p_version}) + endif() + endforeach() - # If the user specified CUDAToolkit_ROOT but nvcc could not be found, this is an error. - if(NOT _CUDA_NVCC_EXECUTABLE AND (DEFINED CUDAToolkit_ROOT OR DEFINED ENV{CUDAToolkit_ROOT})) - set(fail_base "Could not find nvcc executable in path specified by") + # Sort numerically in descending order, so we try the newest versions first. + list(SORT versions COMPARE NATURAL ORDER DESCENDING) - if(DEFINED CUDAToolkit_ROOT) - message(FATAL_ERROR "${fail_base} CUDAToolkit_ROOT=${CUDAToolkit_ROOT}") - elseif(DEFINED ENV{CUDAToolkit_ROOT}) - message(FATAL_ERROR "${fail_base} environment variable CUDAToolkit_ROOT=$ENV{CUDAToolkit_ROOT}") - endif() - endif() + # With a descending list of versions, populate possible paths to search. + set(search_paths) + foreach(v ${versions}) + list(APPEND search_paths "${platform_base}${v}") + endforeach() - # CUDAToolkit_ROOT cmake/env variable not specified, try platform defaults. - # - # - Linux: /usr/local/cuda-X.Y - # - macOS: /Developer/NVIDIA/CUDA-X.Y - # - Windows: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vX.Y - # - # We will also search the default symlink location /usr/local/cuda first since - # if CUDAToolkit_ROOT is not specified, it is assumed that the symlinked - # directory is the desired location. - if(NOT _CUDA_NVCC_EXECUTABLE) - if(UNIX) - if(NOT APPLE) - set(platform_base "/usr/local/cuda-") - else() - set(platform_base "/Developer/NVIDIA/CUDA-") - endif() - else() - set(platform_base "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v") - endif() + # Force the global default /usr/local/cuda to the front on Unix. + if(UNIX) + list(INSERT search_paths 0 "/usr/local/cuda") + endif() - # Build out a descending list of possible cuda installations, e.g. - file(GLOB possible_paths "${platform_base}*") - # Iterate the glob results and create a descending list. - set(versions) - foreach(p ${possible_paths}) - # Extract version number from end of string - string(REGEX MATCH "[0-9][0-9]?\\.[0-9]$" p_version ${p}) - if(IS_DIRECTORY ${p} AND p_version) - list(APPEND versions ${p_version}) + # Now search for nvcc again using the platform default search paths. + find_program(_CUDA_NVCC_EXECUTABLE + NAMES nvcc nvcc.exe + PATHS ${search_paths} + PATH_SUFFIXES bin + ) + + # We are done with these variables now, cleanup. + unset(platform_base) + unset(possible_paths) + unset(versions) + unset(search_paths) + + if(NOT _CUDA_NVCC_EXECUTABLE) + message(FATAL_ERROR "Could not find nvcc, please set CUDAToolkit_ROOT.") + endif() endif() - endforeach() - - # Sort numerically in descending order, so we try the newest versions first. - list(SORT versions COMPARE NATURAL ORDER DESCENDING) - - # With a descending list of versions, populate possible paths to search. - set(search_paths) - foreach(v ${versions}) - list(APPEND search_paths "${platform_base}${v}") - endforeach() - - # Force the global default /usr/local/cuda to the front on Unix. - if(UNIX) - list(INSERT search_paths 0 "/usr/local/cuda") endif() - # Now search for nvcc again using the platform default search paths. - find_program(_CUDA_NVCC_EXECUTABLE - NAMES nvcc nvcc.exe - PATHS ${search_paths} - PATH_SUFFIXES bin - ) - - # We are done with these variables now, cleanup. - unset(platform_base) - unset(possible_paths) - unset(versions) - unset(search_paths) - - if(NOT _CUDA_NVCC_EXECUTABLE) - message(FATAL_ERROR "Could not find nvcc, please set CUDAToolkit_ROOT.") + get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${_CUDA_NVCC_EXECUTABLE}" DIRECTORY) + get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}" DIRECTORY) + + # CMAKE_CUDA_COMPILER_LIBRARY_ROOT contains the device library and version file. + # In a non-scattered installation this is equivalent to CMAKE_CUDA_COMPILER_TOOLKIT_ROOT. + # We first check for a non-scattered installation to prefer it over a scattered installation. + if(EXISTS "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/version.txt") + set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}") + elseif(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/cuda/version.txt") + set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_SYSROOT_LINK}/usr/lib/cuda") + elseif(EXISTS "${CMAKE_SYSROOT}/usr/lib/cuda/version.txt") + set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_SYSROOT}/usr/lib/cuda") endif() endif() - get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${_CUDA_NVCC_EXECUTABLE}" DIRECTORY) - get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}" DIRECTORY ABSOLUTE) - - # CMAKE_CUDA_COMPILER_LIBRARY_ROOT contains the device library and version file. - # In a non-scattered installation this is equivalent to CMAKE_CUDA_COMPILER_TOOLKIT_ROOT. - # We first check for a non-scattered installation to prefer it over a scattered installation. - if(EXISTS "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/version.txt") - set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}") - elseif(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/cuda/version.txt") - set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_SYSROOT_LINK}/usr/lib/cuda") - elseif(EXISTS "${CMAKE_SYSROOT}/usr/lib/cuda/version.txt") - set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_SYSROOT}/usr/lib/cuda") - endif() + set(CMAKE_CUDA_COMPILER_ID_FLAGS_ALWAYS "-v") if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") set(nvcc_test_flags "--keep --keep-dir tmp") @@ -242,10 +235,20 @@ if(NOT CMAKE_CUDA_COMPILER_ID_RUN) # We also use it to verify that CMAKE_CUDA_ARCHITECTURES and additionaly on Clang that CUDA toolkit path works. # The latter could be done during compiler testing in the future to avoid doing this for Clang. # We need to unset the compiler ID otherwise CMAKE_DETERMINE_COMPILER_ID() doesn't work. - unset(CMAKE_CUDA_COMPILER_ID) + set(CMAKE_CUDA_COMPILER_ID) + set(CMAKE_CUDA_PLATFORM_ID) + file(READ ${CMAKE_ROOT}/Modules/CMakePlatformId.h.in + CMAKE_CUDA_COMPILER_ID_PLATFORM_CONTENT) CMAKE_DETERMINE_COMPILER_ID(CUDA CUDAFLAGS CMakeCUDACompilerId.cu) + if(${CMAKE_GENERATOR} MATCHES "Visual Studio") + # Now that we have the path to nvcc, we can compute the toolkit root. + get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER}" DIRECTORY) + get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}" DIRECTORY) + set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}") + endif() + _cmake_find_compiler_sysroot(CUDA) endif() diff --git a/Modules/Compiler/ARMClang.cmake b/Modules/Compiler/ARMClang.cmake index d412399..01ce91d 100644 --- a/Modules/Compiler/ARMClang.cmake +++ b/Modules/Compiler/ARMClang.cmake @@ -61,7 +61,7 @@ function(__armlink_set_cpu_list lang out_var) if(__CMAKE_ARMClang_USING_armlink) set(__linker_wrapper_flags "") else() - set(__linker_wrapper_flags --target=${CMAKE_${lang}_COMPILER_TARGET} -XLinker) + set(__linker_wrapper_flags --target=${CMAKE_${lang}_COMPILER_TARGET} -Xlinker) endif() execute_process(COMMAND "${CMAKE_LINKER}" ${__linker_wrapper_flags} --cpu=list diff --git a/Modules/FindBLAS.cmake b/Modules/FindBLAS.cmake index 4c569b3..c5d791e 100644 --- a/Modules/FindBLAS.cmake +++ b/Modules/FindBLAS.cmake @@ -483,7 +483,9 @@ if(BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All") endif() set(BLAS_mkl_LIB_PATH_SUFFIXES "compiler/lib" "compiler/lib/${BLAS_mkl_ARCH_NAME}_${BLAS_mkl_OS_NAME}" + "compiler/lib/${BLAS_mkl_ARCH_NAME}" "mkl/lib" "mkl/lib/${BLAS_mkl_ARCH_NAME}_${BLAS_mkl_OS_NAME}" + "mkl/lib/${BLAS_mkl_ARCH_NAME}" "lib/${BLAS_mkl_ARCH_NAME}_${BLAS_mkl_OS_NAME}") foreach(IT ${BLAS_SEARCH_LIBS}) diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake index 00d1a50..47bc546 100644 --- a/Modules/FindCUDAToolkit.cmake +++ b/Modules/FindCUDAToolkit.cmake @@ -154,6 +154,8 @@ Targets Created: - ``CUDA::cublas`` - ``CUDA::cublas_static`` +- ``CUDA::cublasLt`` starting in CUDA 10.1 +- ``CUDA::cublasLt_static`` starting in CUDA 10.1 .. _`cuda_toolkit_cuFFT`: @@ -240,6 +242,7 @@ Targets Created: - ``CUDA::nppicc_static`` - `nppicom`: JPEG compression and decompression functions in `nppi_compression_functions.h` + Removed starting in CUDA 11.0, use :ref:`nvJPEG<cuda_toolkit_nvJPEG>` instead. - ``CUDA::nppicom`` - ``CUDA::nppicom_static`` @@ -302,6 +305,7 @@ nvGRAPH """"""" The `nvGRAPH <https://docs.nvidia.com/cuda/nvgraph/index.html>`_ library. +Removed starting in CUDA 11.0 Targets Created: @@ -821,7 +825,7 @@ if(CUDAToolkit_FOUND) endif() _CUDAToolkit_find_and_add_import_lib(culibos) # it's a static library - foreach (cuda_lib cublas cufft curand cusparse nppc nvjpeg) + foreach (cuda_lib cublasLt cublas cufft curand cusparse nppc nvjpeg) _CUDAToolkit_find_and_add_import_lib(${cuda_lib}) _CUDAToolkit_find_and_add_import_lib(${cuda_lib}_static DEPS culibos) endforeach() diff --git a/Modules/FindLAPACK.cmake b/Modules/FindLAPACK.cmake index e275946..a18cec4 100644 --- a/Modules/FindLAPACK.cmake +++ b/Modules/FindLAPACK.cmake @@ -289,7 +289,9 @@ if(BLAS_FOUND) endif() set(LAPACK_mkl_LIB_PATH_SUFFIXES "compiler/lib" "compiler/lib/${LAPACK_mkl_ARCH_NAME}_${LAPACK_mkl_OS_NAME}" + "compiler/lib/${LAPACK_mkl_ARCH_NAME}" "mkl/lib" "mkl/lib/${LAPACK_mkl_ARCH_NAME}_${LAPACK_mkl_OS_NAME}" + "mkl/lib/${LAPACK_mkl_ARCH_NAME}" "lib/${LAPACK_mkl_ARCH_NAME}_${LAPACK_mkl_OS_NAME}") # First try empty lapack libs diff --git a/Modules/GoogleTest.cmake b/Modules/GoogleTest.cmake index 975ce6c..f75d6ad 100644 --- a/Modules/GoogleTest.cmake +++ b/Modules/GoogleTest.cmake @@ -155,7 +155,7 @@ same as the Google Test name (i.e. ``suite.testcase``); see also [DISCOVERY_MODE <POST_BUILD|PRE_TEST>] ) - ``gtest_discover_tests`` sets up a post-build command on the test executable + ``gtest_discover_tests()`` sets up a post-build command on the test executable that generates the list of tests by parsing the output from running the test with the ``--gtest_list_tests`` argument. Compared to the source parsing approach of :command:`gtest_add_tests`, this ensures that the full list of @@ -212,7 +212,7 @@ same as the Google Test name (i.e. ``suite.testcase``); see also ``PROPERTIES name1 value1...`` Specifies additional properties to be set on all tests discovered by this - invocation of ``gtest_discover_tests``. + invocation of ``gtest_discover_tests()``. ``TEST_LIST var`` Make the list of tests available in the variable ``var``, rather than the @@ -246,7 +246,7 @@ same as the Google Test name (i.e. ``suite.testcase``); see also XML result output when using parallel test execution. ``DISCOVERY_MODE`` - Provides greater control over when ``gtest_discover_tests``performs test + Provides greater control over when ``gtest_discover_tests()`` performs test discovery. By default, ``POST_BUILD`` sets up a post-build command to perform test discovery at build time. In certain scenarios, like cross-compiling, this ``POST_BUILD`` behavior is not desirable. @@ -257,7 +257,7 @@ same as the Google Test name (i.e. ``suite.testcase``); see also ``DISCOVERY_MODE`` defaults to the value of the ``CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE`` variable if it is not - passed when calling ``gtest_discover_tests``. This provides a mechanism + passed when calling ``gtest_discover_tests()``. This provides a mechanism for globally selecting a preferred test discovery behavior without having to modify each call site. diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 40bf305..1d3dcce 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 18) -set(CMake_VERSION_PATCH 20200617) +set(CMake_VERSION_PATCH 20200619) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index a7acadc..677bc0f 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -25,6 +25,148 @@ #include "cmVersion.h" #include "cmake.h" +namespace { +class LanguageStandardState +{ +public: + LanguageStandardState(std::string&& lang) + : IsEnabled(false) + , DidStandard(false) + , DidStandardRequired(false) + , DidExtensions(false) + , StandardFlag(lang + "_STANDARD") + , RequiredFlag(lang + "_STANDARD_REQUIRED") + , ExtensionFlag(lang + "_EXTENSIONS") + { + } + + void Enabled(bool isEnabled) { this->IsEnabled = isEnabled; } + + bool UpdateIfMatches(std::vector<std::string> const& argv, size_t& index) + { + bool updated = false; + if (argv[index] == this->StandardFlag) { + this->DidStandard = true; + this->StandardValue = argv[++index]; + updated = true; + } else if (argv[index] == this->RequiredFlag) { + this->DidStandardRequired = true; + this->RequiredValue = argv[++index]; + updated = true; + } else if (argv[index] == this->ExtensionFlag) { + this->DidExtensions = true; + this->ExtensionValue = argv[++index]; + updated = true; + } + return updated; + } + + bool Validate(cmMakefile* const makefile) const + { + if (this->DidStandard) { + makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(this->StandardFlag, + " allowed only in source file signature.")); + return false; + } + if (this->DidStandardRequired) { + makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(this->RequiredFlag, + " allowed only in source file signature.")); + return false; + } + if (this->DidExtensions) { + makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(this->ExtensionFlag, + " allowed only in source file signature.")); + return false; + } + + return true; + } + + bool DidNone() const + { + return !this->DidStandard && !this->DidStandardRequired && + !this->DidExtensions; + } + + void LoadUnsetPropertyValues(cmMakefile* const makefile, bool honorStandard, + bool warnCMP0067, + std::vector<std::string>& warnCMP0067Variables) + { + if (!this->IsEnabled) { + return; + } + + auto lookupStdVar = [&](std::string const& var) -> std::string { + std::string value = makefile->GetSafeDefinition(var); + if (warnCMP0067 && !value.empty()) { + value.clear(); + warnCMP0067Variables.push_back(var); + } + return value; + }; + + if (honorStandard || warnCMP0067) { + if (!this->DidStandard) { + this->StandardValue = + lookupStdVar(cmStrCat("CMAKE_", this->StandardFlag)); + } + if (!this->DidStandardRequired) { + this->RequiredValue = + lookupStdVar(cmStrCat("CMAKE_", this->RequiredFlag)); + } + if (!this->DidExtensions) { + this->ExtensionValue = + lookupStdVar(cmStrCat("CMAKE_", this->ExtensionFlag)); + } + } + } + + void WriteProperties(FILE* fout, std::string const& targetName) const + { + if (!this->IsEnabled) { + return; + } + + auto writeProp = [&](std::string const& prop, std::string const& value) { + fprintf(fout, "set_property(TARGET %s PROPERTY %s %s)\n", + targetName.c_str(), + cmOutputConverter::EscapeForCMake(prop).c_str(), + cmOutputConverter::EscapeForCMake(value).c_str()); + }; + + if (!this->StandardValue.empty()) { + writeProp(this->StandardFlag, this->StandardValue); + } + if (!this->RequiredValue.empty()) { + writeProp(this->RequiredFlag, this->RequiredValue); + } + if (!this->ExtensionValue.empty()) { + writeProp(this->ExtensionFlag, this->ExtensionValue); + } + } + +private: + bool IsEnabled; + bool DidStandard; + bool DidStandardRequired; + bool DidExtensions; + + std::string StandardFlag; + std::string RequiredFlag; + std::string ExtensionFlag; + + std::string StandardValue; + std::string RequiredValue; + std::string ExtensionValue; +}; +} + static std::string const kCMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN = "CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN"; static std::string const kCMAKE_C_COMPILER_TARGET = "CMAKE_C_COMPILER_TARGET"; @@ -79,25 +221,6 @@ static std::set<std::string> ghs_platform_vars{ "GHS_OS_DIR_OPTION" }; -static void writeProperty(FILE* fout, std::string const& targetName, - std::string const& prop, std::string const& value) -{ - fprintf(fout, "set_property(TARGET %s PROPERTY %s %s)\n", targetName.c_str(), - cmOutputConverter::EscapeForCMake(prop).c_str(), - cmOutputConverter::EscapeForCMake(value).c_str()); -} - -std::string cmCoreTryCompile::LookupStdVar(std::string const& var, - bool warnCMP0067) -{ - std::string value = this->Makefile->GetSafeDefinition(var); - if (warnCMP0067 && !value.empty()) { - value.clear(); - this->WarnCMP0067.push_back(var); - } - return value; -} - int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, bool isTryRun) { @@ -137,21 +260,11 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, std::string outputVariable; std::string copyFile; std::string copyFileError; - std::string cStandard; - std::string objcStandard; - std::string cxxStandard; - std::string objcxxStandard; - std::string cudaStandard; - std::string cStandardRequired; - std::string cxxStandardRequired; - std::string objcStandardRequired; - std::string objcxxStandardRequired; - std::string cudaStandardRequired; - std::string cExtensions; - std::string cxxExtensions; - std::string objcExtensions; - std::string objcxxExtensions; - std::string cudaExtensions; + LanguageStandardState cState("C"); + LanguageStandardState cudaState("CUDA"); + LanguageStandardState cxxState("CXX"); + LanguageStandardState objcState("OBJC"); + LanguageStandardState objcxxState("OBJCXX"); std::vector<std::string> targets; std::vector<std::string> linkOptions; std::string libsToLink = " "; @@ -160,21 +273,6 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, bool didOutputVariable = false; bool didCopyFile = false; bool didCopyFileError = false; - bool didCStandard = false; - bool didCxxStandard = false; - bool didObjCStandard = false; - bool didObjCxxStandard = false; - bool didCudaStandard = false; - bool didCStandardRequired = false; - bool didCxxStandardRequired = false; - bool didObjCStandardRequired = false; - bool didObjCxxStandardRequired = false; - bool didCudaStandardRequired = false; - bool didCExtensions = false; - bool didCxxExtensions = false; - bool didObjCExtensions = false; - bool didObjCxxExtensions = false; - bool didCudaExtensions = false; bool useSources = argv[2] == "SOURCES"; std::vector<std::string> sources; @@ -188,21 +286,6 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, DoingOutputVariable, DoingCopyFile, DoingCopyFileError, - DoingCStandard, - DoingCxxStandard, - DoingObjCStandard, - DoingObjCxxStandard, - DoingCudaStandard, - DoingCStandardRequired, - DoingCxxStandardRequired, - DoingObjCStandardRequired, - DoingObjCxxStandardRequired, - DoingCudaStandardRequired, - DoingCExtensions, - DoingCxxExtensions, - DoingObjCExtensions, - DoingObjCxxExtensions, - DoingCudaExtensions, DoingSources, DoingCMakeInternal }; @@ -226,51 +309,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, } else if (argv[i] == "COPY_FILE_ERROR") { doing = DoingCopyFileError; didCopyFileError = true; - } else if (argv[i] == "C_STANDARD") { - doing = DoingCStandard; - didCStandard = true; - } else if (argv[i] == "CXX_STANDARD") { - doing = DoingCxxStandard; - didCxxStandard = true; - } else if (argv[i] == "OBJC_STANDARD") { - doing = DoingObjCStandard; - didObjCStandard = true; - } else if (argv[i] == "OBJCXX_STANDARD") { - doing = DoingObjCxxStandard; - didObjCxxStandard = true; - } else if (argv[i] == "CUDA_STANDARD") { - doing = DoingCudaStandard; - didCudaStandard = true; - } else if (argv[i] == "C_STANDARD_REQUIRED") { - doing = DoingCStandardRequired; - didCStandardRequired = true; - } else if (argv[i] == "CXX_STANDARD_REQUIRED") { - doing = DoingCxxStandardRequired; - didCxxStandardRequired = true; - } else if (argv[i] == "OBJC_STANDARD_REQUIRED") { - doing = DoingObjCStandardRequired; - didObjCStandardRequired = true; - } else if (argv[i] == "OBJCXX_STANDARD_REQUIRED") { - doing = DoingObjCxxStandardRequired; - didObjCxxStandardRequired = true; - } else if (argv[i] == "CUDA_STANDARD_REQUIRED") { - doing = DoingCudaStandardRequired; - didCudaStandardRequired = true; - } else if (argv[i] == "C_EXTENSIONS") { - doing = DoingCExtensions; - didCExtensions = true; - } else if (argv[i] == "CXX_EXTENSIONS") { - doing = DoingCxxExtensions; - didCxxExtensions = true; - } else if (argv[i] == "OBJC_EXTENSIONS") { - doing = DoingObjCExtensions; - didObjCExtensions = true; - } else if (argv[i] == "OBJCXX_EXTENSIONS") { - doing = DoingObjCxxExtensions; - didObjCxxExtensions = true; - } else if (argv[i] == "CUDA_EXTENSIONS") { - doing = DoingCudaExtensions; - didCudaExtensions = true; + } else if (cState.UpdateIfMatches(argv, i) || + cxxState.UpdateIfMatches(argv, i) || + cudaState.UpdateIfMatches(argv, i) || + objcState.UpdateIfMatches(argv, i) || + objcxxState.UpdateIfMatches(argv, i)) { + continue; } else if (argv[i] == "__CMAKE_INTERNAL") { doing = DoingCMakeInternal; } else if (doing == DoingCMakeFlags) { @@ -315,51 +359,6 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, } else if (doing == DoingCopyFileError) { copyFileError = argv[i]; doing = DoingNone; - } else if (doing == DoingCStandard) { - cStandard = argv[i]; - doing = DoingNone; - } else if (doing == DoingCxxStandard) { - cxxStandard = argv[i]; - doing = DoingNone; - } else if (doing == DoingObjCStandard) { - objcStandard = argv[i]; - doing = DoingNone; - } else if (doing == DoingObjCxxStandard) { - objcxxStandard = argv[i]; - doing = DoingNone; - } else if (doing == DoingCudaStandard) { - cudaStandard = argv[i]; - doing = DoingNone; - } else if (doing == DoingCStandardRequired) { - cStandardRequired = argv[i]; - doing = DoingNone; - } else if (doing == DoingCxxStandardRequired) { - cxxStandardRequired = argv[i]; - doing = DoingNone; - } else if (doing == DoingObjCStandardRequired) { - objcStandardRequired = argv[i]; - doing = DoingNone; - } else if (doing == DoingObjCxxStandardRequired) { - objcxxStandardRequired = argv[i]; - doing = DoingNone; - } else if (doing == DoingCudaStandardRequired) { - cudaStandardRequired = argv[i]; - doing = DoingNone; - } else if (doing == DoingCExtensions) { - cExtensions = argv[i]; - doing = DoingNone; - } else if (doing == DoingCxxExtensions) { - cxxExtensions = argv[i]; - doing = DoingNone; - } else if (doing == DoingObjCExtensions) { - objcExtensions = argv[i]; - doing = DoingNone; - } else if (doing == DoingObjCxxExtensions) { - objcxxExtensions = argv[i]; - doing = DoingNone; - } else if (doing == DoingCudaExtensions) { - cudaExtensions = argv[i]; - doing = DoingNone; } else if (doing == DoingSources) { sources.push_back(argv[i]); } else if (doing == DoingCMakeInternal) { @@ -411,59 +410,22 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, return -1; } - if (didCStandard && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "C_STANDARD allowed only in source file signature."); - return -1; - } - if (didCxxStandard && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "CXX_STANDARD allowed only in source file signature."); - return -1; - } - if (didCudaStandard && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "CUDA_STANDARD allowed only in source file signature."); - return -1; - } - if (didCStandardRequired && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "C_STANDARD_REQUIRED allowed only in source file signature."); - return -1; - } - if (didCxxStandardRequired && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "CXX_STANDARD_REQUIRED allowed only in source file signature."); - return -1; - } - if (didCudaStandardRequired && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "CUDA_STANDARD_REQUIRED allowed only in source file signature."); - return -1; - } - if (didCExtensions && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "C_EXTENSIONS allowed only in source file signature."); - return -1; - } - if (didCxxExtensions && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "CXX_EXTENSIONS allowed only in source file signature."); - return -1; - } - if (didCudaExtensions && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "CUDA_EXTENSIONS allowed only in source file signature."); - return -1; + if (!this->SrcFileSignature) { + if (!cState.Validate(this->Makefile)) { + return -1; + } + if (!cudaState.Validate(this->Makefile)) { + return -1; + } + if (!cxxState.Validate(this->Makefile)) { + return -1; + } + if (!objcState.Validate(this->Makefile)) { + return -1; + } + if (!objcxxState.Validate(this->Makefile)) { + return -1; + } } // compute the binary dir when TRY_COMPILE is called with a src file @@ -819,21 +781,17 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, } fprintf(fout, ")\n"); - bool const testC = testLangs.find("C") != testLangs.end(); - bool const testObjC = testLangs.find("OBJC") != testLangs.end(); - bool const testCxx = testLangs.find("CXX") != testLangs.end(); - bool const testObjCxx = testLangs.find("OBJCXX") != testLangs.end(); - bool const testCuda = testLangs.find("CUDA") != testLangs.end(); + cState.Enabled(testLangs.find("C") != testLangs.end()); + cxxState.Enabled(testLangs.find("CXX") != testLangs.end()); + cudaState.Enabled(testLangs.find("CUDA") != testLangs.end()); + objcState.Enabled(testLangs.find("OBJC") != testLangs.end()); + objcxxState.Enabled(testLangs.find("OBJCXX") != testLangs.end()); bool warnCMP0067 = false; bool honorStandard = true; - if (!didCStandard && !didCxxStandard && !didObjCStandard && - !didObjCxxStandard && !didCudaStandard && !didCStandardRequired && - !didCxxStandardRequired && !didObjCStandardRequired && - !didObjCxxStandardRequired && !didCudaStandardRequired && - !didCExtensions && !didCxxExtensions && !didObjCExtensions && - !didObjCxxExtensions && !didCudaExtensions) { + if (cState.DidNone() && cxxState.DidNone() && objcState.DidNone() && + objcxxState.DidNone() && cudaState.DidNone()) { switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0067)) { case cmPolicies::WARN: warnCMP0067 = this->Makefile->PolicyOptionalWarningEnabled( @@ -855,46 +813,20 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, } } - if (honorStandard || warnCMP0067) { + std::vector<std::string> warnCMP0067Variables; - auto testLanguage = - [&](bool testLang, bool didLangStandard, bool didLangStandardRequired, - bool didLangExtensions, std::string& langStandard, - std::string& langStandardRequired, std::string& langExtensions, - const std::string& lang) { - if (testLang) { - if (!didLangStandard) { - langStandard = this->LookupStdVar( - cmStrCat("CMAKE_", lang, "_STANDARD"), warnCMP0067); - } - if (!didLangStandardRequired) { - langStandardRequired = this->LookupStdVar( - cmStrCat("CMAKE_", lang, "_STANDARD_REQUIRED"), warnCMP0067); - } - if (!didLangExtensions) { - langExtensions = this->LookupStdVar( - cmStrCat("CMAKE_", lang, "_EXTENSIONS"), warnCMP0067); - } - } - }; - - testLanguage(testC, didCStandard, didCStandardRequired, didCExtensions, - cStandard, cStandardRequired, cExtensions, "C"); - testLanguage(testObjC, didObjCStandard, didObjCStandardRequired, - didObjCExtensions, objcStandard, objcStandardRequired, - objcExtensions, "OBJC"); - testLanguage(testCxx, didCxxStandard, didCxxStandardRequired, - didCxxExtensions, cxxStandard, cxxStandardRequired, - cxxExtensions, "CXX"); - testLanguage(testObjCxx, didObjCxxStandard, didObjCxxStandardRequired, - didObjCxxExtensions, objcxxStandard, objcxxStandardRequired, - objcxxExtensions, "OBJCXX"); - testLanguage(testCuda, didCudaStandard, didCudaStandardRequired, - didCudaExtensions, cudaStandard, cudaStandardRequired, - cudaExtensions, "CUDA"); - } + cState.LoadUnsetPropertyValues(this->Makefile, honorStandard, warnCMP0067, + warnCMP0067Variables); + cxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard, + warnCMP0067, warnCMP0067Variables); + cudaState.LoadUnsetPropertyValues(this->Makefile, honorStandard, + warnCMP0067, warnCMP0067Variables); + objcState.LoadUnsetPropertyValues(this->Makefile, honorStandard, + warnCMP0067, warnCMP0067Variables); + objcxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard, + warnCMP0067, warnCMP0067Variables); - if (!this->WarnCMP0067.empty()) { + if (!warnCMP0067Variables.empty()) { std::ostringstream w; /* clang-format off */ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0067) << "\n" @@ -902,43 +834,17 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, "is not honoring language standard variables in the test project:\n" ; /* clang-format on */ - for (std::string const& vi : this->WarnCMP0067) { + for (std::string const& vi : warnCMP0067Variables) { w << " " << vi << "\n"; } this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str()); } - auto writeLanguageProperties = [&](bool testLang, - const std::string& langStandard, - const std::string& langStandardRequired, - const std::string& langExtensions, - const std::string& lang) { - if (testLang) { - if (!langStandard.empty()) { - writeProperty(fout, targetName, cmStrCat(lang, "_STANDARD"), - langStandard); - } - if (!langStandardRequired.empty()) { - writeProperty(fout, targetName, cmStrCat(lang, "_STANDARD_REQUIRED"), - langStandardRequired); - } - if (!langExtensions.empty()) { - writeProperty(fout, targetName, cmStrCat(lang, "_EXTENSIONS"), - langExtensions); - } - } - }; - - writeLanguageProperties(testC, cStandard, cStandardRequired, cExtensions, - "C"); - writeLanguageProperties(testObjC, objcStandard, objcStandardRequired, - objcExtensions, "OBJC"); - writeLanguageProperties(testCxx, cxxStandard, cxxStandardRequired, - cxxExtensions, "CXX"); - writeLanguageProperties(testObjCxx, objcxxStandard, objcxxStandardRequired, - objcxxExtensions, "OBJCXX"); - writeLanguageProperties(testCuda, cudaStandard, cudaStandardRequired, - cudaExtensions, "CUDA"); + cState.WriteProperties(fout, targetName); + cxxState.WriteProperties(fout, targetName); + cudaState.WriteProperties(fout, targetName); + objcState.WriteProperties(fout, targetName); + objcxxState.WriteProperties(fout, targetName); if (!linkOptions.empty()) { std::vector<std::string> options; @@ -1050,7 +956,9 @@ void cmCoreTryCompile::CleanupFiles(std::string const& binDir) std::set<std::string> deletedFiles; for (unsigned long i = 0; i < dir.GetNumberOfFiles(); ++i) { const char* fileName = dir.GetFile(i); - if (strcmp(fileName, ".") != 0 && strcmp(fileName, "..") != 0) { + if (strcmp(fileName, ".") != 0 && strcmp(fileName, "..") != 0 && + // Do not delete NFS temporary files. + !cmHasPrefix(fileName, ".nfs")) { if (deletedFiles.insert(fileName).second) { std::string const fullPath = std::string(binDir).append("/").append(fileName); diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h index ae714a6..916572a 100644 --- a/Source/cmCoreTryCompile.h +++ b/Source/cmCoreTryCompile.h @@ -47,10 +47,6 @@ protected: std::string OutputFile; std::string FindErrorMessage; bool SrcFileSignature = false; - -private: - std::vector<std::string> WarnCMP0067; - std::string LookupStdVar(std::string const& var, bool warnCMP0067); }; #endif diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index e4fb67e..3e0c21c 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -1708,7 +1708,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode std::string error; std::string lang; if (!context->LG->GetMakefile()->CompileFeatureKnown( - context->HeadTarget->Target, p, lang, &error)) { + context->HeadTarget->Target->GetName(), p, lang, &error)) { reportError(context, content->GetOriginalExpression(), error); return std::string(); } @@ -1742,9 +1742,9 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode continue; } if (!context->LG->GetMakefile()->HaveStandardAvailable( - target->Target, lit.first, it)) { + target, lit.first, context->Config, it)) { if (evalLL) { - cmProp l = target->GetProperty(lit.first + "_STANDARD"); + cmProp l = target->GetLanguageStandard(lit.first, context->Config); if (!l) { l = standardDefault; } diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index f2011ee..1f66a9f 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -947,6 +947,45 @@ bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const return it != this->ExplicitObjectName.end(); } +cmProp cmGeneratorTarget::GetLanguageStandard(std::string const& lang, + std::string const& config) const +{ + std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang); + auto langStandardIter = this->LanguageStandardMap.find(key); + if (langStandardIter != this->LanguageStandardMap.end()) { + return &langStandardIter->second; + } + + return this->Target->GetProperty(cmStrCat(lang, "_STANDARD")); +} + +cmProp cmGeneratorTarget::GetLanguageStandardProperty(std::string const& lang, + const char* suffix) const +{ + cmProp propertyValue = this->Target->GetProperty(cmStrCat(lang, suffix)); + if (propertyValue == nullptr) { + // Check if we should use the value set by another language. + if (lang == "OBJC") { + propertyValue = this->GetLanguageStandardProperty("C", suffix); + } else if (lang == "OBJCXX" || lang == "CUDA") { + propertyValue = this->GetLanguageStandardProperty("CXX", suffix); + } + } + return propertyValue; +} + +cmProp cmGeneratorTarget::GetLanguageExtensions(std::string const& lang) const +{ + return this->GetLanguageStandardProperty(lang, "_EXTENSIONS"); +} + +bool cmGeneratorTarget::GetLanguageStandardRequired( + std::string const& lang) const +{ + cmProp p = this->GetLanguageStandardProperty(lang, "_STANDARD_REQUIRED"); + return p && cmIsOn(*p); +} + void cmGeneratorTarget::GetModuleDefinitionSources( std::vector<cmSourceFile const*>& data, const std::string& config) const { @@ -4408,12 +4447,68 @@ void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const bool cmGeneratorTarget::ComputeCompileFeatures(std::string const& config) const { + // Compute the language standard based on the compile features. std::vector<BT<std::string>> features = this->GetCompileFeatures(config); for (BT<std::string> const& f : features) { - if (!this->Makefile->AddRequiredTargetFeature(this->Target, f.Value)) { + std::string lang; + if (!this->Makefile->CompileFeatureKnown(this->Target->GetName(), f.Value, + lang, nullptr)) { return false; } + + std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang); + cmProp currentLanguageStandard = this->GetLanguageStandard(lang, config); + + std::string newRequiredStandard; + if (!this->Makefile->GetNewRequiredStandard( + this->Target->GetName(), f.Value, currentLanguageStandard, + newRequiredStandard)) { + return false; + } + + if (!newRequiredStandard.empty()) { + this->LanguageStandardMap[key] = newRequiredStandard; + } } + + return true; +} + +bool cmGeneratorTarget::ComputeCompileFeatures( + std::string const& config, std::set<LanguagePair> const& languagePairs) const +{ + for (const auto& language : languagePairs) { + cmProp generatorTargetLanguageStandard = + this->GetLanguageStandard(language.first, config); + if (!generatorTargetLanguageStandard) { + // If the standard isn't explicitly set we copy it over from the + // specified paired language. + std::string key = + cmStrCat(cmSystemTools::UpperCase(config), '-', language.first); + cmProp standardToCopy = + this->GetLanguageStandard(language.second, config); + if (standardToCopy != nullptr) { + this->LanguageStandardMap[key] = *standardToCopy; + generatorTargetLanguageStandard = &this->LanguageStandardMap[key]; + } else { + cmProp defaultStandard = this->Makefile->GetDef( + cmStrCat("CMAKE_", language.second, "_STANDARD_DEFAULT")); + if (defaultStandard != nullptr) { + this->LanguageStandardMap[key] = *defaultStandard; + generatorTargetLanguageStandard = &this->LanguageStandardMap[key]; + } + } + + // Custom updates for the CUDA standard. + if (generatorTargetLanguageStandard != nullptr && + language.first == "CUDA") { + if (*generatorTargetLanguageStandard == "98") { + this->LanguageStandardMap[key] = "03"; + } + } + } + } + return true; } diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 3aedbf5..a71e64c 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -148,6 +148,13 @@ public: bool HasExplicitObjectName(cmSourceFile const* file) const; void AddExplicitObjectName(cmSourceFile const* sf); + cmProp GetLanguageStandard(std::string const& lang, + std::string const& config) const; + + cmProp GetLanguageExtensions(std::string const& lang) const; + + bool GetLanguageStandardRequired(std::string const& lang) const; + void GetModuleDefinitionSources(std::vector<cmSourceFile const*>&, const std::string& config) const; void GetExternalObjects(std::vector<cmSourceFile const*>&, @@ -515,6 +522,11 @@ public: bool ComputeCompileFeatures(std::string const& config) const; + using LanguagePair = std::pair<std::string, std::string>; + bool ComputeCompileFeatures( + std::string const& config, + std::set<LanguagePair> const& languagePairs) const; + /** * Trace through the source files in this target and add al source files * that they depend on, used by all generators @@ -1038,6 +1050,11 @@ private: bool GetRPATH(const std::string& config, const std::string& prop, std::string& rpath) const; + mutable std::map<std::string, std::string> LanguageStandardMap; + + cmProp GetLanguageStandardProperty(std::string const& lang, + const char* suffix) const; + public: const std::vector<const cmGeneratorTarget*>& GetLinkImplementationClosure( const std::string& config) const; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 1ed5e8b..4b4ffda 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1442,12 +1442,10 @@ bool cmGlobalGenerator::Compute() localGen->AddHelperCommands(); } - // Finalize the set of compile features for each target. - // FIXME: This turns into calls to cmMakefile::AddRequiredTargetFeature - // which actually modifies the <lang>_STANDARD target property - // on the original cmTarget instance. It accumulates features - // across all configurations. Some refactoring is needed to - // compute a per-config resulta purely during generation. + // Perform up-front computation in order to handle errors (such as unknown + // features) at this point. While processing the compile features we also + // calculate and cache the language standard required by the compile + // features. for (const auto& localGen : this->LocalGenerators) { if (!localGen->ComputeTargetCompileFeatures()) { return false; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 4d589ed..bb422eb 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1152,23 +1152,24 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( } // organize the sources - std::vector<cmSourceFile*> classes; - if (!gtgt->GetConfigCommonSourceFiles(classes)) { + std::vector<cmSourceFile*> commonSourceFiles; + if (!gtgt->GetConfigCommonSourceFiles(commonSourceFiles)) { return false; } // Add CMakeLists.txt file for user convenience. - this->AddXCodeProjBuildRule(gtgt, classes); + this->AddXCodeProjBuildRule(gtgt, commonSourceFiles); // Add the Info.plist we are about to generate for an App Bundle. if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) { std::string plist = this->ComputeInfoPListLocation(gtgt); cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource( plist, true, cmSourceFileLocationKind::Known); - classes.push_back(sf); + commonSourceFiles.push_back(sf); } - std::sort(classes.begin(), classes.end(), cmSourceFilePathCompare()); + std::sort(commonSourceFiles.begin(), commonSourceFiles.end(), + cmSourceFilePathCompare()); gtgt->ComputeObjectMapping(); @@ -1176,7 +1177,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( std::vector<cmXCodeObject*> headerFiles; std::vector<cmXCodeObject*> resourceFiles; std::vector<cmXCodeObject*> sourceFiles; - for (auto sourceFile : classes) { + for (auto sourceFile : commonSourceFiles) { cmXCodeObject* xsf = this->CreateXCodeSourceFile( this->CurrentLocalGenerator, sourceFile, gtgt); cmXCodeObject* fr = xsf->GetObject("fileRef"); @@ -1275,7 +1276,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( using mapOfVectorOfSourceFiles = std::map<std::string, std::vector<cmSourceFile*>>; mapOfVectorOfSourceFiles bundleFiles; - for (auto sourceFile : classes) { + for (auto sourceFile : commonSourceFiles) { cmGeneratorTarget::SourceFileFlags tsFlags = gtgt->GetTargetSourceFileFlags(sourceFile); if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeMacContent) { @@ -1323,7 +1324,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( using mapOfVectorOfSourceFiles = std::map<std::string, std::vector<cmSourceFile*>>; mapOfVectorOfSourceFiles bundleFiles; - for (auto sourceFile : classes) { + for (auto sourceFile : commonSourceFiles) { cmGeneratorTarget::SourceFileFlags tsFlags = gtgt->GetTargetSourceFileFlags(sourceFile); if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeDeepResource) { @@ -1353,22 +1354,20 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( } } - // create framework build phase + // always create framework build phase cmXCodeObject* frameworkBuildPhase = nullptr; - if (!externalObjFiles.empty()) { - frameworkBuildPhase = - this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase); - frameworkBuildPhase->SetComment("Frameworks"); - frameworkBuildPhase->AddAttribute("buildActionMask", - this->CreateString("2147483647")); - buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); - frameworkBuildPhase->AddAttribute("files", buildFiles); - for (auto& externalObjFile : externalObjFiles) { - buildFiles->AddObject(externalObjFile); - } - frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", - this->CreateString("0")); - } + frameworkBuildPhase = + this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase); + frameworkBuildPhase->SetComment("Frameworks"); + frameworkBuildPhase->AddAttribute("buildActionMask", + this->CreateString("2147483647")); + buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); + frameworkBuildPhase->AddAttribute("files", buildFiles); + for (auto& externalObjFile : externalObjFiles) { + buildFiles->AddObject(externalObjFile); + } + frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", + this->CreateString("0")); // create list of build phases and create the Xcode target cmXCodeObject* buildPhases = this->CreateObject(cmXCodeObject::OBJECT_LIST); @@ -2768,6 +2767,156 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) } } + // Separate libraries into ones that can be linked using "Link Binary With + // Libraries" build phase and the ones that can't. Only targets that build + // Apple bundles (.app, .framework, .bundle) can use this feature and only + // targets that represent actual libraries (static or dynamic, local or + // imported) not objects and not executables will be used. These are + // limitations imposed by CMake use-cases - otherwise a lot of things break. + // The rest will be linked using linker flags (OTHER_LDFLAGS setting in Xcode + // project). + std::map<std::string, std::vector<cmComputeLinkInformation::Item const*>> + configItemMap; + auto addToLinkerArguments = + [&configItemMap](const std::string& configName, + cmComputeLinkInformation::Item const* libItemPtr) { + auto& linkVector = configItemMap[configName]; + if (std::find_if(linkVector.begin(), linkVector.end(), + [libItemPtr](cmComputeLinkInformation::Item const* p) { + return p == libItemPtr; + }) == linkVector.end()) { + linkVector.push_back(libItemPtr); + } + }; + std::vector<cmComputeLinkInformation::Item const*> linkPhaseTargetVector; + std::map<std::string, std::vector<std::string>> targetConfigMap; + using ConfigItemPair = + std::pair<std::string, cmComputeLinkInformation::Item const*>; + std::map<std::string, std::vector<ConfigItemPair>> targetItemMap; + std::map<std::string, std::vector<std::string>> targetProductNameMap; + for (auto const& configName : this->CurrentConfigurationTypes) { + cmComputeLinkInformation* cli = gt->GetLinkInformation(configName); + if (!cli) { + continue; + } + for (auto const& libItem : cli->GetItems()) { + // TODO: Drop this check once we have option to add outside libraries to + // Xcode project + auto* libTarget = FindXCodeTarget(libItem.Target); + if (gt->IsBundleOnApple() && + (gt->GetType() == cmStateEnums::EXECUTABLE || + gt->GetType() == cmStateEnums::SHARED_LIBRARY || + gt->GetType() == cmStateEnums::MODULE_LIBRARY || + gt->GetType() == cmStateEnums::UNKNOWN_LIBRARY) && + (libTarget && libItem.Target && + (libItem.Target->GetType() == cmStateEnums::STATIC_LIBRARY || + libItem.Target->GetType() == cmStateEnums::SHARED_LIBRARY || + libItem.Target->GetType() == cmStateEnums::MODULE_LIBRARY))) { + // Add unique configuration name to target-config map for later + // checks + std::string libName = libItem.Target->GetName(); + auto& configVector = targetConfigMap[libName]; + if (std::find(configVector.begin(), configVector.end(), configName) == + configVector.end()) { + configVector.push_back(configName); + } + // Add a pair of config and item to target-item map + auto& itemVector = targetItemMap[libName]; + itemVector.emplace_back(ConfigItemPair(configName, &libItem)); + // Add product file-name to a lib-product map + auto productName = cmSystemTools::GetFilenameName(libItem.Value.Value); + auto& productVector = targetProductNameMap[libName]; + if (std::find(productVector.begin(), productVector.end(), + productName) == productVector.end()) { + productVector.push_back(productName); + } + } else { + // Add this library item to a regular linker flag list + addToLinkerArguments(configName, &libItem); + } + } + } + + // Go through target library map and separate libraries that are linked + // in all configurations and produce only single product, from the rest. + // Only these will be linked through "Link Binary With Libraries" build + // phase. + for (auto const& targetLibConfigs : targetConfigMap) { + // Add this library to "Link Binary With Libraries" build phase if it's + // linked in all configurations and it has only one product name + auto& itemVector = targetItemMap[targetLibConfigs.first]; + auto& productVector = targetProductNameMap[targetLibConfigs.first]; + if (targetLibConfigs.second == this->CurrentConfigurationTypes && + productVector.size() == 1) { + // Add this library to "Link Binary With Libraries" list + linkPhaseTargetVector.push_back(itemVector[0].second); + } else { + for (auto const& libItem : targetItemMap[targetLibConfigs.first]) { + // Add this library item to a regular linker flag list + addToLinkerArguments(libItem.first, libItem.second); + } + } + } + + // Add libraries to "Link Binary With Libraries" build phase and collect + // their search paths. Xcode does not support per-configuration linking + // in this build phase so we don't have to do this for each configuration + // separately. + std::vector<std::string> linkSearchPaths; + for (auto const& libItem : linkPhaseTargetVector) { + // Add target output directory as a library search path + std::string linkDir = cmSystemTools::GetParentDirectory( + libItem->Target->GetLocationForBuild()); + if (std::find(linkSearchPaths.begin(), linkSearchPaths.end(), linkDir) == + linkSearchPaths.end()) { + linkSearchPaths.push_back(linkDir); + } + // Add target dependency + auto const& libName = *libItem; + if (!libName.Target->IsImported()) { + for (auto const& configName : this->CurrentConfigurationTypes) { + target->AddDependTarget(configName, libName.Target->GetName()); + } + } + // Get the library target + auto* libTarget = FindXCodeTarget(libItem->Target); + if (!libTarget) { + continue; + } + // Add the target output file as a build reference for other targets + // to link against + auto* fileRefObject = libTarget->GetObject("productReference"); + if (!fileRefObject) { + continue; + } + cmXCodeObject* buildFile; + auto it = FileRefToBuildFileMap.find(fileRefObject); + if (it == FileRefToBuildFileMap.end()) { + buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile); + buildFile->AddAttribute("fileRef", fileRefObject); + FileRefToBuildFileMap[fileRefObject] = buildFile; + } else { + buildFile = it->second; + } + // Add this reference to current target + auto* buildPhases = target->GetObject("buildPhases"); + if (!buildPhases) { + continue; + } + auto* frameworkBuildPhase = + buildPhases->GetObject(cmXCodeObject::PBXFrameworksBuildPhase); + if (!frameworkBuildPhase) { + continue; + } + auto* buildFiles = frameworkBuildPhase->GetObject("files"); + if (!buildFiles) { + continue; + } + if (!buildFiles->HasObject(buildFile)) { + buildFiles->AddObject(buildFile); + } + } + // Loop over configuration types and set per-configuration info. for (auto const& configName : this->CurrentConfigurationTypes) { { @@ -2795,21 +2944,20 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) } // Compute the link library and directory information. - cmComputeLinkInformation* pcli = gt->GetLinkInformation(configName); - if (!pcli) { + cmComputeLinkInformation* cli = gt->GetLinkInformation(configName); + if (!cli) { continue; } - cmComputeLinkInformation& cli = *pcli; // Add dependencies directly on library files. - for (auto const& libDep : cli.GetDepends()) { + for (auto const& libDep : cli->GetDepends()) { target->AddDependLibrary(configName, libDep); } // add the library search paths { std::string linkDirs; - for (auto const& libDir : cli.GetDirectories()) { + for (auto const& libDir : cli->GetDirectories()) { if (!libDir.empty() && libDir != "/usr/lib") { // Now add the same one but append // $(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) to it: @@ -2820,15 +2968,22 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) linkDirs += this->XCodeEscapePath(libDir); } } + // Add previously collected paths where to look for libraries + // that were added to "Link Binary With Libraries" + for (auto& linkDir : linkSearchPaths) { + linkDirs += " "; + linkDirs += this->XCodeEscapePath(linkDir); + } this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS", linkDirs.c_str(), configName); } - // now add the link libraries + // now add the left-over link libraries { std::string linkLibs; const char* sep = ""; - for (auto const& libName : cli.GetItems()) { + for (auto const& libItem : configItemMap[configName]) { + auto const& libName = *libItem; linkLibs += sep; sep = " "; if (libName.IsPath) { diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index e380f1c..0fc6558 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -28,7 +28,7 @@ struct cmDocumentationEntry; /** \class cmGlobalXCodeGenerator * \brief Write a Unix makefiles. * - * cmGlobalXCodeGenerator manages UNIX build process for a tree + * cmGlobalXCodeGenerator manages Xcode build process for a tree */ class cmGlobalXCodeGenerator : public cmGlobalGenerator { @@ -295,6 +295,7 @@ private: std::map<std::string, cmXCodeObject*> TargetGroup; std::map<std::string, cmXCodeObject*> FileRefs; std::map<cmGeneratorTarget const*, cmXCodeObject*> XCodeObjectMap; + std::map<cmXCodeObject*, cmXCodeObject*> FileRefToBuildFileMap; std::vector<std::string> Architectures; std::string ObjectDirArchDefault; std::string ObjectDirArch; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 3b3f110..95caa30 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -803,39 +803,8 @@ bool cmLocalGenerator::ComputeTargetCompileFeatures() // Now that C/C++ _STANDARD values have been computed // set the values to ObjC/ObjCXX _STANDARD variables if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { - auto copyStandardToObjLang = [&](LanguagePair const& lang) -> bool { - if (!target->GetProperty(cmStrCat(lang.first, "_STANDARD"))) { - cmProp standard = - target->GetProperty(cmStrCat(lang.second, "_STANDARD")); - if (!standard) { - standard = this->Makefile->GetDef( - cmStrCat("CMAKE_", lang.second, "_STANDARD_DEFAULT")); - } - target->Target->SetProperty(cmStrCat(lang.first, "_STANDARD"), - standard ? standard->c_str() : nullptr); - return true; - } - return false; - }; - auto copyPropertyToObjLang = [&](LanguagePair const& lang, - const char* property) { - if (!target->GetProperty(cmStrCat(lang.first, property)) && - target->GetProperty(cmStrCat(lang.second, property))) { - cmProp p = target->GetProperty(cmStrCat(lang.second, property)); - target->Target->SetProperty(cmStrCat(lang.first, property), - p ? p->c_str() : nullptr); - } - }; - for (auto const& lang : pairedLanguages) { - if (copyStandardToObjLang(lang)) { - copyPropertyToObjLang(lang, "_STANDARD_REQUIRED"); - copyPropertyToObjLang(lang, "_EXTENSIONS"); - } - } - if (cmProp standard = target->GetProperty("CUDA_STANDARD")) { - if (*standard == "98") { - target->Target->SetProperty("CUDA_STANDARD", "03"); - } + for (std::string const& c : configNames) { + target->ComputeCompileFeatures(c, inferredEnabledLanguages); } } } @@ -1026,7 +995,7 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags, } for (auto const& it : target->GetMaxLanguageStandards()) { - cmProp standard = target->GetProperty(it.first + "_STANDARD"); + cmProp standard = target->GetLanguageStandard(it.first, config); if (!standard) { continue; } @@ -1050,7 +1019,7 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags, } std::string compReqFlag; - this->AddCompilerRequirementFlag(compReqFlag, target, lang); + this->AddCompilerRequirementFlag(compReqFlag, target, lang, config); if (!compReqFlag.empty()) { flags.emplace_back(std::move(compReqFlag)); } @@ -2046,7 +2015,7 @@ void cmLocalGenerator::AddLanguageFlagsForLinking( // when linking in order to use the matching standard library. // FIXME: If CMake gains an abstraction for standard library // selection, this will have to be reconciled with it. - this->AddCompilerRequirementFlag(flags, target, lang); + this->AddCompilerRequirementFlag(flags, target, lang, config); } this->AddLanguageFlags(flags, target, lang, config); @@ -2189,7 +2158,8 @@ void cmLocalGenerator::AddSharedFlags(std::string& flags, } void cmLocalGenerator::AddCompilerRequirementFlag( - std::string& flags, cmGeneratorTarget const* target, const std::string& lang) + std::string& flags, cmGeneratorTarget const* target, const std::string& lang, + const std::string& config) { if (lang.empty()) { return; @@ -2200,15 +2170,13 @@ void cmLocalGenerator::AddCompilerRequirementFlag( // This compiler has no notion of language standard levels. return; } - std::string extProp = lang + "_EXTENSIONS"; bool ext = true; - if (cmProp extPropValue = target->GetProperty(extProp)) { + if (cmProp extPropValue = target->GetLanguageExtensions(lang)) { if (cmIsOff(*extPropValue)) { ext = false; } } - std::string stdProp = lang + "_STANDARD"; - cmProp standardProp = target->GetProperty(stdProp); + cmProp standardProp = target->GetLanguageStandard(lang, config); if (!standardProp) { if (ext) { // No language standard is specified and extensions are not disabled. @@ -2228,7 +2196,7 @@ void cmLocalGenerator::AddCompilerRequirementFlag( std::string const type = ext ? "EXTENSION" : "STANDARD"; - if (target->GetPropertyAsBool(lang + "_STANDARD_REQUIRED")) { + if (target->GetLanguageStandardRequired(lang)) { std::string option_flag = "CMAKE_" + lang + *standardProp + "_" + type + "_COMPILE_OPTION"; diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index f2d9145..f4781d6 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -123,7 +123,8 @@ public: const std::string& config); void AddCompilerRequirementFlag(std::string& flags, cmGeneratorTarget const* target, - const std::string& lang); + const std::string& lang, + const std::string& config); //! Append flags to a string. virtual void AppendFlags(std::string& flags, const std::string& newFlags) const; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 5c3063b..1f1c06a 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -39,6 +39,7 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorExpressionEvaluationFile.h" +#include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmInstallGenerator.h" // IWYU pragma: keep #include "cmInstallSubdirectoryGenerator.h" @@ -4027,6 +4028,8 @@ int cmMakefile::ConfigureFile(const std::string& infile, if (copyonly) { if (!cmSystemTools::CopyFileIfDifferent(sinfile, soutfile)) { + this->IssueMessage(MessageType::FATAL_ERROR, + cmSystemTools::GetLastSystemError()); return 0; } } else { @@ -4077,9 +4080,15 @@ int cmMakefile::ConfigureFile(const std::string& infile, fin.close(); fout.close(); if (!cmSystemTools::CopyFileIfDifferent(tempOutputFile, soutfile)) { + this->IssueMessage(MessageType::FATAL_ERROR, + cmSystemTools::GetLastSystemError()); res = 0; } else { - cmSystemTools::SetPermissions(soutfile, perm); + if (!cmSystemTools::SetPermissions(soutfile, perm)) { + this->IssueMessage(MessageType::FATAL_ERROR, + cmSystemTools::GetLastSystemError()); + res = 0; + } } cmSystemTools::RemoveFile(tempOutputFile); } @@ -4673,7 +4682,33 @@ bool cmMakefile::AddRequiredTargetFeature(cmTarget* target, } std::string lang; - if (!this->CompileFeatureKnown(target, feature, lang, error)) { + if (!this->CheckCompileFeaturesAvailable(target->GetName(), feature, lang, + error)) { + return false; + } + + target->AppendProperty("COMPILE_FEATURES", feature); + + // FIXME: Add a policy to avoid updating the <LANG>_STANDARD target + // property due to COMPILE_FEATURES. The language standard selection + // should be done purely at generate time based on whatever the project + // code put in these properties explicitly. That is mostly true now, + // but for compatibility we need to continue updating the property here. + if (lang == "C" || lang == "OBJC") { + return this->AddRequiredTargetCFeature(target, feature, lang, error); + } + if (lang == "CUDA") { + return this->AddRequiredTargetCudaFeature(target, feature, lang, error); + } + return this->AddRequiredTargetCxxFeature(target, feature, lang, error); +} + +bool cmMakefile::CheckCompileFeaturesAvailable(const std::string& targetName, + const std::string& feature, + std::string& lang, + std::string* error) const +{ + if (!this->CompileFeatureKnown(targetName, feature, lang, error)) { return false; } @@ -4699,18 +4734,10 @@ bool cmMakefile::AddRequiredTargetFeature(cmTarget* target, return false; } - target->AppendProperty("COMPILE_FEATURES", feature); - - if (lang == "C" || lang == "OBJC") { - return this->AddRequiredTargetCFeature(target, feature, lang, error); - } - if (lang == "CUDA") { - return this->AddRequiredTargetCudaFeature(target, feature, lang, error); - } - return this->AddRequiredTargetCxxFeature(target, feature, lang, error); + return true; } -bool cmMakefile::CompileFeatureKnown(cmTarget const* target, +bool cmMakefile::CompileFeatureKnown(const std::string& targetName, const std::string& feature, std::string& lang, std::string* error) const @@ -4747,7 +4774,7 @@ bool cmMakefile::CompileFeatureKnown(cmTarget const* target, e << " unknown feature \"" << feature << "\" for " "target \"" - << target->GetName() << "\"."; + << targetName << "\"."; if (error) { *error = e.str(); } else { @@ -4802,22 +4829,50 @@ const char* cmMakefile::CompileFeaturesAvailable(const std::string& lang, return featuresKnown; } -bool cmMakefile::HaveStandardAvailable(cmTarget const* target, +bool cmMakefile::GetNewRequiredStandard(const std::string& targetName, + const std::string& feature, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error) const +{ + std::string lang; + if (!this->CheckCompileFeaturesAvailable(targetName, feature, lang, error)) { + return false; + } + + if (lang == "C" || lang == "OBJC") { + return this->GetNewRequiredCStandard(targetName, feature, lang, + currentLangStandardValue, + newRequiredStandard, error); + } + if (lang == "CUDA") { + return this->GetNewRequiredCudaStandard(targetName, feature, lang, + currentLangStandardValue, + newRequiredStandard, error); + } + return this->GetNewRequiredCxxStandard(targetName, feature, lang, + currentLangStandardValue, + newRequiredStandard, error); +} + +bool cmMakefile::HaveStandardAvailable(cmGeneratorTarget const* target, std::string const& lang, + std::string const& config, const std::string& feature) const { if (lang == "C" || lang == "OBJC") { - return this->HaveCStandardAvailable(target, feature, lang); + return this->HaveCStandardAvailable(target, lang, config, feature); } if (lang == "CUDA") { - return this->HaveCudaStandardAvailable(target, feature, lang); + return this->HaveCudaStandardAvailable(target, lang, config, feature); } - return this->HaveCxxStandardAvailable(target, feature, lang); + return this->HaveCxxStandardAvailable(target, lang, config, feature); } -bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const +bool cmMakefile::HaveCStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, + const std::string& feature) const { cmProp defaultCStandard = this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); @@ -4846,7 +4901,7 @@ bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, this->CheckNeededCLanguage(feature, lang, needC90, needC99, needC11); - cmProp existingCStandard = target->GetProperty(cmStrCat(lang, "_STANDARD")); + cmProp existingCStandard = target->GetLanguageStandard(lang, config); if (!existingCStandard) { existingCStandard = defaultCStandard; } @@ -4909,9 +4964,10 @@ bool cmMakefile::IsLaterStandard(std::string const& lang, cm::cend(CXX_STANDARDS); } -bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const +bool cmMakefile::HaveCxxStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, + const std::string& feature) const { cmProp defaultCxxStandard = this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); @@ -4941,8 +4997,7 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, this->CheckNeededCxxLanguage(feature, lang, needCxx98, needCxx11, needCxx14, needCxx17, needCxx20); - cmProp existingCxxStandard = - target->GetProperty(cmStrCat(lang, "_STANDARD")); + cmProp existingCxxStandard = target->GetLanguageStandard(lang, config); if (!existingCxxStandard) { existingCxxStandard = defaultCxxStandard; } @@ -5009,6 +5064,29 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, std::string const& lang, std::string* error) const { + std::string newRequiredStandard; + if (this->GetNewRequiredCxxStandard( + target->GetName(), feature, lang, + target->GetProperty(cmStrCat(lang, "_STANDARD")), newRequiredStandard, + error)) { + if (!newRequiredStandard.empty()) { + target->SetProperty(cmStrCat(lang, "_STANDARD"), newRequiredStandard); + } + return true; + } + + return false; +} + +bool cmMakefile::GetNewRequiredCxxStandard(const std::string& targetName, + const std::string& feature, + std::string const& lang, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error) const +{ + newRequiredStandard.clear(); + bool needCxx98 = false; bool needCxx11 = false; bool needCxx14 = false; @@ -5018,8 +5096,7 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, this->CheckNeededCxxLanguage(feature, lang, needCxx98, needCxx11, needCxx14, needCxx17, needCxx20); - cmProp existingCxxStandard = - target->GetProperty(cmStrCat(lang, "_STANDARD")); + cmProp existingCxxStandard = currentLangStandardValue; if (existingCxxStandard == nullptr) { cmProp defaultCxxStandard = this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); @@ -5034,7 +5111,7 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, cmStrCmp(*existingCxxStandard)); if (existingCxxLevel == cm::cend(CXX_STANDARDS)) { const std::string e = cmStrCat( - "The ", lang, "_STANDARD property on target \"", target->GetName(), + "The ", lang, "_STANDARD property on target \"", targetName, "\" contained an invalid value: \"", *existingCxxStandard, "\"."); if (error) { *error = e; @@ -5060,16 +5137,17 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, // Ensure the C++ language level is high enough to support // the needed C++ features. if (!existingCxxLevel || existingCxxLevel < needCxxLevel) { - target->SetProperty(cmStrCat(lang, "_STANDARD"), *needCxxLevel); + newRequiredStandard = *needCxxLevel; } } return true; } -bool cmMakefile::HaveCudaStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const +bool cmMakefile::HaveCudaStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, + const std::string& feature) const { cmProp defaultCudaStandard = this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); @@ -5100,8 +5178,7 @@ bool cmMakefile::HaveCudaStandardAvailable(cmTarget const* target, this->CheckNeededCudaLanguage(feature, lang, needCuda03, needCuda11, needCuda14, needCuda17, needCuda20); - cmProp existingCudaStandard = - target->GetProperty(cmStrCat(lang, "_STANDARD")); + cmProp existingCudaStandard = target->GetLanguageStandard(lang, config); if (!existingCudaStandard) { existingCudaStandard = defaultCudaStandard; } @@ -5168,6 +5245,28 @@ bool cmMakefile::AddRequiredTargetCudaFeature(cmTarget* target, std::string const& lang, std::string* error) const { + std::string newRequiredStandard; + if (this->GetNewRequiredCudaStandard( + target->GetName(), feature, lang, + target->GetProperty(cmStrCat(lang, "_STANDARD")), newRequiredStandard, + error)) { + if (!newRequiredStandard.empty()) { + target->SetProperty(cmStrCat(lang, "_STANDARD"), newRequiredStandard); + } + return true; + } + return false; +} + +bool cmMakefile::GetNewRequiredCudaStandard(const std::string& targetName, + const std::string& feature, + std::string const& lang, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error) const +{ + newRequiredStandard.clear(); + bool needCuda03 = false; bool needCuda11 = false; bool needCuda14 = false; @@ -5177,8 +5276,7 @@ bool cmMakefile::AddRequiredTargetCudaFeature(cmTarget* target, this->CheckNeededCudaLanguage(feature, lang, needCuda03, needCuda11, needCuda14, needCuda17, needCuda20); - cmProp existingCudaStandard = - target->GetProperty(cmStrCat(lang, "_STANDARD")); + cmProp existingCudaStandard = currentLangStandardValue; if (existingCudaStandard == nullptr) { cmProp defaultCudaStandard = this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); @@ -5193,7 +5291,7 @@ bool cmMakefile::AddRequiredTargetCudaFeature(cmTarget* target, cmStrCmp(*existingCudaStandard)); if (existingCudaLevel == cm::cend(CUDA_STANDARDS)) { const std::string e = cmStrCat( - "The ", lang, "_STANDARD property on target \"", target->GetName(), + "The ", lang, "_STANDARD property on target \"", targetName, "\" contained an invalid value: \"", *existingCudaStandard, "\"."); if (error) { *error = e; @@ -5219,7 +5317,7 @@ bool cmMakefile::AddRequiredTargetCudaFeature(cmTarget* target, // Ensure the CUDA language level is high enough to support // the needed CUDA features. if (!existingCudaLevel || existingCudaLevel < needCudaLevel) { - target->SetProperty("CUDA_STANDARD", *needCudaLevel); + newRequiredStandard = *needCudaLevel; } } @@ -5252,13 +5350,36 @@ bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target, std::string const& lang, std::string* error) const { + std::string newRequiredStandard; + if (this->GetNewRequiredCStandard( + target->GetName(), feature, lang, + target->GetProperty(cmStrCat(lang, "_STANDARD")), newRequiredStandard, + error)) { + if (!newRequiredStandard.empty()) { + target->SetProperty(cmStrCat(lang, "_STANDARD"), newRequiredStandard); + } + return true; + } + + return false; +} + +bool cmMakefile::GetNewRequiredCStandard(const std::string& targetName, + const std::string& feature, + std::string const& lang, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error) const +{ + newRequiredStandard.clear(); + bool needC90 = false; bool needC99 = false; bool needC11 = false; this->CheckNeededCLanguage(feature, lang, needC90, needC99, needC11); - cmProp existingCStandard = target->GetProperty(cmStrCat(lang, "_STANDARD")); + cmProp existingCStandard = currentLangStandardValue; if (existingCStandard == nullptr) { cmProp defaultCStandard = this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); @@ -5270,7 +5391,7 @@ bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target, if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), cmStrCmp(*existingCStandard)) == cm::cend(C_STANDARDS)) { const std::string e = cmStrCat( - "The ", lang, "_STANDARD property on target \"", target->GetName(), + "The ", lang, "_STANDARD property on target \"", targetName, "\" contained an invalid value: \"", *existingCStandard, "\"."); if (error) { *error = e; @@ -5307,11 +5428,11 @@ bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target, } if (setC11) { - target->SetProperty(cmStrCat(lang, "_STANDARD"), "11"); + newRequiredStandard = "11"; } else if (setC99) { - target->SetProperty(cmStrCat(lang, "_STANDARD"), "99"); + newRequiredStandard = "99"; } else if (setC90) { - target->SetProperty(cmStrCat(lang, "_STANDARD"), "90"); + newRequiredStandard = "90"; } return true; } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 45d7109..332554e 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -47,6 +47,7 @@ class cmExpandedCommandArgument; class cmExportBuildFileGenerator; class cmFunctionBlocker; class cmGeneratorExpressionEvaluationFile; +class cmGeneratorTarget; class cmGlobalGenerator; class cmImplicitDependsList; class cmInstallGenerator; @@ -928,13 +929,22 @@ public: bool AddRequiredTargetFeature(cmTarget* target, const std::string& feature, std::string* error = nullptr) const; - bool CompileFeatureKnown(cmTarget const* target, const std::string& feature, - std::string& lang, std::string* error) const; + bool CompileFeatureKnown(const std::string& targetName, + const std::string& feature, std::string& lang, + std::string* error) const; const char* CompileFeaturesAvailable(const std::string& lang, std::string* error) const; - bool HaveStandardAvailable(cmTarget const* target, std::string const& lang, + bool GetNewRequiredStandard(const std::string& targetName, + const std::string& feature, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error = nullptr) const; + + bool HaveStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, const std::string& feature) const; bool IsLaterStandard(std::string const& lang, std::string const& lhs, @@ -1174,6 +1184,11 @@ private: std::string const& lang, std::string* error = nullptr) const; + bool CheckCompileFeaturesAvailable(const std::string& targetName, + const std::string& feature, + std::string& lang, + std::string* error) const; + void CheckNeededCLanguage(const std::string& feature, std::string const& lang, bool& needC90, bool& needC99, bool& needC11) const; @@ -1186,15 +1201,37 @@ private: bool& needCuda11, bool& needCuda14, bool& needCuda17, bool& needCuda20) const; - bool HaveCStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const; - bool HaveCxxStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const; - bool HaveCudaStandardAvailable(cmTarget const* target, + bool GetNewRequiredCStandard(const std::string& targetName, + const std::string& feature, + std::string const& lang, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error = nullptr) const; + bool GetNewRequiredCxxStandard(const std::string& targetName, const std::string& feature, - std::string const& lang) const; + std::string const& lang, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error = nullptr) const; + bool GetNewRequiredCudaStandard(const std::string& targetName, + const std::string& feature, + std::string const& lang, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error = nullptr) const; + + bool HaveCStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, + const std::string& feature) const; + bool HaveCxxStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, + const std::string& feature) const; + bool HaveCudaStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, + const std::string& feature) const; void CheckForUnusedVariables() const; diff --git a/Tests/Cuda/Toolkit/CMakeLists.txt b/Tests/Cuda/Toolkit/CMakeLists.txt index 86b4652..00125e3 100644 --- a/Tests/Cuda/Toolkit/CMakeLists.txt +++ b/Tests/Cuda/Toolkit/CMakeLists.txt @@ -14,15 +14,29 @@ message(STATUS "CUDAToolkit_INCLUDE_DIRS: ${CUDAToolkit_INCLUDE_DIRS}") message(STATUS "CUDAToolkit_LIBRARY_DIR: ${CUDAToolkit_LIBRARY_DIR}") message(STATUS "CUDAToolkit_NVCC_EXECUTABLE ${CUDAToolkit_NVCC_EXECUTABLE}") -# Verify that all the CUDA:: targets exist even when the CUDA language isn't enabled +set(cuda_libs cudart cuda_driver cublas cufft cufftw curand cusolver cusparse) +if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 10.1) + list(APPEND cuda_libs cublasLt) +endif() +if(CUDAToolkit_VERSION_MAJOR VERSION_LESS 11) + list(APPEND cuda_libs nvgraph) +endif() -foreach (cuda_lib cudart cuda_driver cublas cufft cufftw curand cusolver cusparse nvgraph) +# Verify that all the CUDA:: targets exist even when the CUDA language isn't enabled +foreach (cuda_lib IN LISTS cuda_libs) + if(NOT CUDA_${cuda_lib}_LIBRARY) + message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found") + endif() if(NOT TARGET CUDA::${cuda_lib}) - message(FATAL_ERROR "The CUDA::${cuda_lib} target was expected but couldn't be found") + message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found") endif() endforeach() -foreach (cuda_lib nppc nppial nppicc nppidei nppif nppig nppim nppist nppitc npps nppicom nppisu) +set(npp_libs nppc nppial nppicc nppidei nppif nppig nppim nppist nppitc npps nppisu) +if(CUDAToolkit_VERSION_MAJOR VERSION_LESS 11) + list(APPEND npp_libs nppicom) +endif() +foreach (cuda_lib IN LISTS npp_libs) if(NOT TARGET CUDA::${cuda_lib}) message(FATAL_ERROR "The CUDA::${cuda_lib} target was expected but couldn't be found") endif() diff --git a/Tests/CudaOnly/Toolkit/CMakeLists.txt b/Tests/CudaOnly/Toolkit/CMakeLists.txt index 0d5d574..bb06ba8 100644 --- a/Tests/CudaOnly/Toolkit/CMakeLists.txt +++ b/Tests/CudaOnly/Toolkit/CMakeLists.txt @@ -11,8 +11,17 @@ message(STATUS "CUDAToolkit_INCLUDE_DIRS: ${CUDAToolkit_INCLUDE_DIRS}") message(STATUS "CUDAToolkit_LIBRARY_DIR: ${CUDAToolkit_LIBRARY_DIR}") message(STATUS "CUDAToolkit_NVCC_EXECUTABLE ${CUDAToolkit_NVCC_EXECUTABLE}") + +set(cuda_libs cudart cuda_driver cublas cufft cufftw curand cusolver cusparse) +if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 10.1) + list(APPEND cuda_libs cublasLt) +endif() +if(CUDAToolkit_VERSION_MAJOR VERSION_LESS 11) + list(APPEND cuda_libs nvgraph) +endif() + # Verify that all the CUDA:: targets and variables exist -foreach (cuda_lib cudart cuda_driver cublas cufft cufftw curand cusolver cusparse nvgraph) +foreach (cuda_lib IN LISTS cuda_libs) if(NOT CUDA_${cuda_lib}_LIBRARY) message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found") endif() @@ -21,7 +30,11 @@ foreach (cuda_lib cudart cuda_driver cublas cufft cufftw curand cusolver cuspars endif() endforeach() -foreach (cuda_lib nppc nppial nppicc nppidei nppif nppig nppim nppist nppitc npps nppicom nppisu) +set(npp_libs nppc nppial nppicc nppidei nppif nppig nppim nppist nppitc npps nppisu) +if(CUDAToolkit_VERSION_MAJOR VERSION_LESS 11) + list(APPEND npp_libs nppicom) +endif() +foreach (cuda_lib ) if(NOT CUDA_${cuda_lib}_LIBRARY) message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found") endif() diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 866e7c0..6c634b5 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -494,6 +494,9 @@ add_RunCMake_test(File_Generate) add_RunCMake_test(ExportWithoutLanguage) add_RunCMake_test(target_link_directories) 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(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}) diff --git a/Tests/RunCMake/target_link_libraries/AliasTargets.cmake b/Tests/RunCMake/target_link_libraries-ALIAS/AliasTargets.cmake index 73f8a7d..73f8a7d 100644 --- a/Tests/RunCMake/target_link_libraries/AliasTargets.cmake +++ b/Tests/RunCMake/target_link_libraries-ALIAS/AliasTargets.cmake diff --git a/Tests/RunCMake/target_link_libraries-ALIAS/CMakeLists.txt b/Tests/RunCMake/target_link_libraries-ALIAS/CMakeLists.txt new file mode 100644 index 0000000..9cf020f --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-ALIAS/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.1) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE) diff --git a/Tests/RunCMake/target_link_libraries-ALIAS/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries-ALIAS/RunCMakeTest.cmake new file mode 100644 index 0000000..4d24a6e --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-ALIAS/RunCMakeTest.cmake @@ -0,0 +1,23 @@ +include(RunCMake) + +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} ${ARGN}) + + unset(RunCMake_TEST_BINARY_DIR) + unset(RunCMake_TEST_NO_CLEAN) +endmacro() + +set(RunCMake_TEST_OUTPUT_MERGE TRUE) +if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG) + set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release) +endif() +run_cmake(AliasTargets) +run_cmake_target(AliasTargets func func --config Release) +run_cmake_target(AliasTargets lib-local lib-local --config Release) +run_cmake_target(AliasTargets main-local main-local --config Release) +run_cmake_target(AliasTargets lib-global lib-global --config Release) +run_cmake_target(AliasTargets main-global main-global --config Release) +unset(RunCMake_TEST_OPTIONS) +unset(RunCMake_TEST_OUTPUT_MERGE) diff --git a/Tests/RunCMake/target_link_libraries/func.c b/Tests/RunCMake/target_link_libraries-ALIAS/func.c index 415a9bf..415a9bf 100644 --- a/Tests/RunCMake/target_link_libraries/func.c +++ b/Tests/RunCMake/target_link_libraries-ALIAS/func.c diff --git a/Tests/RunCMake/target_link_libraries-ALIAS/lib.c b/Tests/RunCMake/target_link_libraries-ALIAS/lib.c new file mode 100644 index 0000000..b2d1b66 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-ALIAS/lib.c @@ -0,0 +1,10 @@ + +#if defined(_WIN32) +__declspec(dllimport) +#endif + void func_c(); + +void lib() +{ + func_c(); +} diff --git a/Tests/RunCMake/target_link_libraries/main.c b/Tests/RunCMake/target_link_libraries-ALIAS/main.c index a908dea..a908dea 100644 --- a/Tests/RunCMake/target_link_libraries/main.c +++ b/Tests/RunCMake/target_link_libraries-ALIAS/main.c diff --git a/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/CMakeLists.txt b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/CMakeLists.txt new file mode 100644 index 0000000..9cf020f --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.1) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE) diff --git a/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/RunCMakeTest.cmake new file mode 100644 index 0000000..0f0e5d8 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/RunCMakeTest.cmake @@ -0,0 +1,41 @@ +include(RunCMake) + +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} ${ARGN}) + + unset(RunCMake_TEST_BINARY_DIR) + unset(RunCMake_TEST_NO_CLEAN) +endmacro() + +run_cmake(bad-usage) + +if (RunCMake_GENERATOR MATCHES "Makefiles|Ninja|Visual Studio|Xcode|Watcom WMake") + + run_cmake(bad-mix-lang) + + set(RunCMake_TEST_OUTPUT_MERGE TRUE) + if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG) + set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release) + endif() + + run_cmake(genex) + + run_cmake_target(genex lib LinkLibraries_lib --config Release) + run_cmake_target(genex lib2 LinkLibraries_lib2 --config Release) + run_cmake_target(genex lib3 LinkLibraries_lib3 --config Release) + run_cmake_target(genex exe LinkLibraries_exe --config Release) + run_cmake_target(genex C_import LinkLibraries_C_import --config Release) + run_cmake_target(genex CXX_import LinkLibraries_CXX_import --config Release) + run_cmake_target(genex C_interface LinkLibraries_C_interface --config Release) + run_cmake_target(genex CXX_interface LinkLibraries_CXX_interface --config Release) + run_cmake_target(genex C_interface2 LinkLibraries_C_interface2 --config Release) + run_cmake_target(genex CXX_interface2 LinkLibraries_CXX_interface2 --config Release) + run_cmake_target(genex C_static LinkLibraries_C_static --config Release) + run_cmake_target(genex CXX_static LinkLibraries_CXX_static --config Release) + + unset(RunCMake_TEST_OPTIONS) + unset(RunCMake_TEST_OUTPUT_MERGE) + +endif() diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-bad-mix-lang-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-mix-lang-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-bad-mix-lang-result.txt +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-mix-lang-result.txt diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-bad-mix-lang-stderr.txt b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-mix-lang-stderr.txt index 2ecdc0c..2ecdc0c 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-bad-mix-lang-stderr.txt +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-mix-lang-stderr.txt diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANGUAGE-bad-mix-lang.cmake b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-mix-lang.cmake index e8efa75..e8efa75 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANGUAGE-bad-mix-lang.cmake +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-mix-lang.cmake diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANGUAGE-bad-usage-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-usage-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANGUAGE-bad-usage-result.txt +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-usage-result.txt diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANGUAGE-bad-usage-stderr.txt b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-usage-stderr.txt index 469f1fe..d61f789 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANGUAGE-bad-usage-stderr.txt +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-usage-stderr.txt @@ -1,4 +1,4 @@ -CMake Error at genex_LINK_LANGUAGE-bad-usage.cmake:4 \(target_link_libraries\): +CMake Error at bad-usage.cmake:4 \(target_link_libraries\): Error evaluating generator expression: \$<LINK_LANGUAGE> diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANGUAGE-bad-usage.cmake b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-usage.cmake index 81cfb0c..81cfb0c 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANGUAGE-bad-usage.cmake +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/bad-usage.cmake diff --git a/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/empty.c b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/empty.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/empty.c diff --git a/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/func.c b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/func.c new file mode 100644 index 0000000..415a9bf --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/func.c @@ -0,0 +1,7 @@ + +#if defined(_WIN32) +__declspec(dllexport) +#endif + void func_c() +{ +} diff --git a/Tests/RunCMake/target_link_libraries/func.cxx b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/func.cxx index a12caca..a12caca 100644 --- a/Tests/RunCMake/target_link_libraries/func.cxx +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/func.cxx diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANGUAGE.cmake b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/genex.cmake index f3fe955..f3fe955 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANGUAGE.cmake +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/genex.cmake diff --git a/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/lib.c b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/lib.c new file mode 100644 index 0000000..b2d1b66 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/lib.c @@ -0,0 +1,10 @@ + +#if defined(_WIN32) +__declspec(dllimport) +#endif + void func_c(); + +void lib() +{ + func_c(); +} diff --git a/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/main.c b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/main.c new file mode 100644 index 0000000..a908dea --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/main.c @@ -0,0 +1,12 @@ + +#if defined(_WIN32) +__declspec(dllimport) +#endif + void func_c(); + +int main() +{ + func_c(); + + return 0; +} diff --git a/Tests/RunCMake/target_link_libraries/main.cxx b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/main.cxx index ffaa3b4..ffaa3b4 100644 --- a/Tests/RunCMake/target_link_libraries/main.cxx +++ b/Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/main.cxx diff --git a/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/CMakeLists.txt b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/CMakeLists.txt new file mode 100644 index 0000000..9cf020f --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.1) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE) diff --git a/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/RunCMakeTest.cmake new file mode 100644 index 0000000..3b16f9e --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/RunCMakeTest.cmake @@ -0,0 +1,38 @@ +include(RunCMake) + +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} ${ARGN}) + + unset(RunCMake_TEST_BINARY_DIR) + unset(RunCMake_TEST_NO_CLEAN) +endmacro() + +if (RunCMake_GENERATOR MATCHES "Makefiles|Ninja|Visual Studio|Xcode|Watcom WMake") + + run_cmake(bad-mix-lang) + + set(RunCMake_TEST_OUTPUT_MERGE TRUE) + if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG) + set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release) + endif() + + run_cmake(genex) + + run_cmake_target(genex lib LinkLibraries_lib --config Release) + run_cmake_target(genex lib2 LinkLibraries_lib2 --config Release) + run_cmake_target(genex lib3 LinkLibraries_lib3 --config Release) + run_cmake_target(genex exe LinkLibraries_exe --config Release) + run_cmake_target(genex C_import LinkLibraries_C_import --config Release) + run_cmake_target(genex CXX_import LinkLibraries_CXX_import --config Release) + run_cmake_target(genex C_interface LinkLibraries_C_interface --config Release) + run_cmake_target(genex CXX_interface LinkLibraries_CXX_interface --config Release) + run_cmake_target(genex C_interface2 LinkLibraries_C_interface2 --config Release) + run_cmake_target(genex CXX_interface2 LinkLibraries_CXX_interface2 --config Release) + run_cmake_target(genex CXX_static LinkLibraries_CXX_static --config Release) + + unset(RunCMake_TEST_OPTIONS) + unset(RunCMake_TEST_OUTPUT_MERGE) + +endif() diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANGUAGE-bad-mix-lang-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/bad-mix-lang-result.txt index d00491f..d00491f 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANGUAGE-bad-mix-lang-result.txt +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/bad-mix-lang-result.txt diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANGUAGE-bad-mix-lang-stderr.txt b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/bad-mix-lang-stderr.txt index 2ecdc0c..2ecdc0c 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANGUAGE-bad-mix-lang-stderr.txt +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/bad-mix-lang-stderr.txt diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-bad-mix-lang.cmake b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/bad-mix-lang.cmake index f80010a..f80010a 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-bad-mix-lang.cmake +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/bad-mix-lang.cmake diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-interface-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/basic-result.txt index 8d98f9d..8d98f9d 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-interface-result.txt +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/basic-result.txt diff --git a/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/empty.c b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/empty.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/empty.c diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-exe_cxx-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/exe_c-result.txt index 8d98f9d..8d98f9d 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-exe_cxx-result.txt +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/exe_c-result.txt diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-exe_c-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/exe_cxx-result.txt index 8d98f9d..8d98f9d 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-exe_c-result.txt +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/exe_cxx-result.txt diff --git a/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/func.c b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/func.c new file mode 100644 index 0000000..415a9bf --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/func.c @@ -0,0 +1,7 @@ + +#if defined(_WIN32) +__declspec(dllexport) +#endif + void func_c() +{ +} diff --git a/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/func.cxx b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/func.cxx new file mode 100644 index 0000000..a12caca --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/func.cxx @@ -0,0 +1,7 @@ + +#if defined(_WIN32) +__declspec(dllexport) +#endif + void func_cxx() +{ +} diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID.cmake b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/genex.cmake index 9feccd0..9feccd0 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID.cmake +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/genex.cmake diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-basic-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/interface-result.txt index 8d98f9d..8d98f9d 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-basic-result.txt +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/interface-result.txt diff --git a/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/lib.c b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/lib.c new file mode 100644 index 0000000..b2d1b66 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/lib.c @@ -0,0 +1,10 @@ + +#if defined(_WIN32) +__declspec(dllimport) +#endif + void func_c(); + +void lib() +{ + func_c(); +} diff --git a/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/main.c b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/main.c new file mode 100644 index 0000000..a908dea --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/main.c @@ -0,0 +1,12 @@ + +#if defined(_WIN32) +__declspec(dllimport) +#endif + void func_c(); + +int main() +{ + func_c(); + + return 0; +} diff --git a/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/main.cxx b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/main.cxx new file mode 100644 index 0000000..ffaa3b4 --- /dev/null +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/main.cxx @@ -0,0 +1,12 @@ + +#if defined(_WIN32) +__declspec(dllimport) +#endif + void func_cxx(); + +int main() +{ + func_cxx(); + + return 0; +} diff --git a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-no_language-result.txt b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/no_language-result.txt index 573541a..573541a 100644 --- a/Tests/RunCMake/target_link_libraries/genex_LINK_LANG_AND_ID-no_language-result.txt +++ b/Tests/RunCMake/target_link_libraries-LINK_LANG_AND_ID/no_language-result.txt diff --git a/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake index 1f4077c..189592d 100644 --- a/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake +++ b/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake @@ -30,71 +30,3 @@ run_cmake(StaticPrivateDepNotExported) run_cmake(StaticPrivateDepNotTarget) run_cmake(UNKNOWN-IMPORTED-GLOBAL) run_cmake(empty_keyword_args) - -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} ${ARGN}) - - unset(RunCMake_TEST_BINARY_DIR) - unset(RunCMake_TEST_NO_CLEAN) -endmacro() - -set(RunCMake_TEST_OUTPUT_MERGE TRUE) -if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG) - set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release) -endif() -run_cmake(AliasTargets) -run_cmake_target(AliasTargets func func --config Release) -run_cmake_target(AliasTargets lib-local lib-local --config Release) -run_cmake_target(AliasTargets main-local main-local --config Release) -run_cmake_target(AliasTargets lib-global lib-global --config Release) -run_cmake_target(AliasTargets main-global main-global --config Release) -unset(RunCMake_TEST_OPTIONS) -unset(RunCMake_TEST_OUTPUT_MERGE) - -run_cmake(genex_LINK_LANGUAGE-bad-usage) - -if (RunCMake_GENERATOR MATCHES "Makefiles|Ninja|Visual Studio|Xcode|Watcom WMake") - - run_cmake(genex_LINK_LANGUAGE-bad-mix-lang) - run_cmake(genex_LINK_LANG_AND_ID-bad-mix-lang) - - set(RunCMake_TEST_OUTPUT_MERGE TRUE) - if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG) - set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release) - endif() - - run_cmake(genex_LINK_LANGUAGE) - - run_cmake_target(genex_LINK_LANGUAGE lib LinkLibraries_lib --config Release) - run_cmake_target(genex_LINK_LANGUAGE lib2 LinkLibraries_lib2 --config Release) - run_cmake_target(genex_LINK_LANGUAGE lib3 LinkLibraries_lib3 --config Release) - run_cmake_target(genex_LINK_LANGUAGE exe LinkLibraries_exe --config Release) - run_cmake_target(genex_LINK_LANGUAGE C_import LinkLibraries_C_import --config Release) - run_cmake_target(genex_LINK_LANGUAGE CXX_import LinkLibraries_CXX_import --config Release) - run_cmake_target(genex_LINK_LANGUAGE C_interface LinkLibraries_C_interface --config Release) - run_cmake_target(genex_LINK_LANGUAGE CXX_interface LinkLibraries_CXX_interface --config Release) - run_cmake_target(genex_LINK_LANGUAGE C_interface2 LinkLibraries_C_interface2 --config Release) - run_cmake_target(genex_LINK_LANGUAGE CXX_interface2 LinkLibraries_CXX_interface2 --config Release) - run_cmake_target(genex_LINK_LANGUAGE C_static LinkLibraries_C_static --config Release) - run_cmake_target(genex_LINK_LANGUAGE CXX_static LinkLibraries_CXX_static --config Release) - - run_cmake(genex_LINK_LANG_AND_ID) - - run_cmake_target(genex_LINK_LANG_AND_ID lib LinkLibraries_lib --config Release) - run_cmake_target(genex_LINK_LANG_AND_ID lib2 LinkLibraries_lib2 --config Release) - run_cmake_target(genex_LINK_LANG_AND_ID lib3 LinkLibraries_lib3 --config Release) - run_cmake_target(genex_LINK_LANG_AND_ID exe LinkLibraries_exe --config Release) - run_cmake_target(genex_LINK_LANG_AND_ID C_import LinkLibraries_C_import --config Release) - run_cmake_target(genex_LINK_LANG_AND_ID CXX_import LinkLibraries_CXX_import --config Release) - run_cmake_target(genex_LINK_LANG_AND_ID C_interface LinkLibraries_C_interface --config Release) - run_cmake_target(genex_LINK_LANG_AND_ID CXX_interface LinkLibraries_CXX_interface --config Release) - run_cmake_target(genex_LINK_LANG_AND_ID C_interface2 LinkLibraries_C_interface2 --config Release) - run_cmake_target(genex_LINK_LANG_AND_ID CXX_interface2 LinkLibraries_CXX_interface2 --config Release) - run_cmake_target(genex_LINK_LANG_AND_ID CXX_static LinkLibraries_CXX_static --config Release) - - unset(RunCMake_TEST_OPTIONS) - unset(RunCMake_TEST_OUTPUT_MERGE) - -endif() |