summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeLists.txt537
-rw-r--r--Source/CMakeVersion.cmake10
-rw-r--r--Source/CPack/cmCPackArchiveGenerator.cxx12
-rw-r--r--Source/CPack/cmCPackConfigure.h.in5
-rw-r--r--Source/CPack/cmCPackDragNDropGenerator.cxx7
-rw-r--r--Source/CPack/cmCPackFreeBSDGenerator.cxx54
-rw-r--r--Source/CPack/cmCPackGeneratorFactory.cxx8
-rw-r--r--Source/CPack/cmCPackGeneratorFactory.h2
-rw-r--r--Source/CPack/cmCPackNSISGenerator.cxx34
-rw-r--r--Source/CPack/cpack.cxx171
-rw-r--r--Source/CTest/cmCTestBuildHandler.cxx35
-rw-r--r--Source/CTest/cmCTestCoverageCommand.cxx12
-rw-r--r--Source/CTest/cmCTestCoverageCommand.h6
-rw-r--r--Source/CTest/cmCTestHandlerCommand.cxx20
-rw-r--r--Source/CTest/cmCTestHandlerCommand.h5
-rw-r--r--Source/CTest/cmCTestRunTest.cxx146
-rw-r--r--Source/CTest/cmCTestSubmitCommand.cxx65
-rw-r--r--Source/CTest/cmCTestSubmitCommand.h13
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx6
-rw-r--r--Source/CTest/cmCTestUploadCommand.cxx2
-rw-r--r--Source/CTest/cmCTestUploadCommand.h5
-rw-r--r--Source/CursesDialog/cmCursesLongMessageForm.cxx6
-rw-r--r--Source/CursesDialog/form/CMakeLists.txt2
-rw-r--r--Source/LexerParser/cmFortranLexer.cxx377
-rw-r--r--Source/LexerParser/cmFortranLexer.in.l16
-rw-r--r--Source/LexerParser/cmFortranParser.cxx324
-rw-r--r--Source/LexerParser/cmFortranParser.y18
-rw-r--r--Source/Modules/CMakeBuildUtilities.cmake379
-rw-r--r--Source/QtDialog/CMakeLists.txt83
-rw-r--r--Source/QtDialog/FirstConfigure.cxx3
-rw-r--r--Source/cmArgumentParser.cxx186
-rw-r--r--Source/cmArgumentParser.h400
-rw-r--r--Source/cmArgumentParserTypes.h69
-rw-r--r--Source/cmBlockCommand.cxx197
-rw-r--r--Source/cmBlockCommand.h14
-rw-r--r--Source/cmCMakeHostSystemInformationCommand.cxx12
-rw-r--r--Source/cmCMakeLanguageCommand.cxx35
-rw-r--r--Source/cmCMakePathCommand.cxx134
-rw-r--r--Source/cmCMakePresetsGraph.cxx166
-rw-r--r--Source/cmCMakePresetsGraph.h65
-rw-r--r--Source/cmCMakePresetsGraphInternal.h4
-rw-r--r--Source/cmCMakePresetsGraphReadJSON.cxx52
-rw-r--r--Source/cmCMakePresetsGraphReadJSONPackagePresets.cxx95
-rw-r--r--Source/cmCommands.cxx16
-rw-r--r--Source/cmComputeLinkInformation.cxx71
-rw-r--r--Source/cmConfigure.cmake.h.in13
-rw-r--r--Source/cmCoreTryCompile.cxx911
-rw-r--r--Source/cmCoreTryCompile.h88
-rw-r--r--Source/cmCreateTestSourceList.cxx4
-rw-r--r--Source/cmCurl.cxx11
-rw-r--r--Source/cmCxxModuleMapper.cxx234
-rw-r--r--Source/cmCxxModuleMapper.h41
-rw-r--r--Source/cmDefinePropertyCommand.cxx5
-rw-r--r--Source/cmDocumentation.cxx42
-rw-r--r--Source/cmExecuteProcessCommand.cxx12
-rw-r--r--Source/cmExecutionStatus.h17
-rw-r--r--Source/cmExperimental.cxx2
-rw-r--r--Source/cmExportBuildFileGenerator.cxx66
-rw-r--r--Source/cmExportBuildFileGenerator.h16
-rw-r--r--Source/cmExportCommand.cxx23
-rw-r--r--Source/cmExportFileGenerator.cxx32
-rw-r--r--Source/cmExportFileGenerator.h5
-rw-r--r--Source/cmExportInstallAndroidMKGenerator.cxx3
-rw-r--r--Source/cmExportInstallFileGenerator.cxx79
-rw-r--r--Source/cmExportInstallFileGenerator.h25
-rw-r--r--Source/cmExportSet.cxx31
-rw-r--r--Source/cmExportSet.h2
-rw-r--r--Source/cmExportTryCompileFileGenerator.h3
-rw-r--r--Source/cmFileAPICodemodel.cxx16
-rw-r--r--Source/cmFileCommand.cxx412
-rw-r--r--Source/cmFindBase.cxx68
-rw-r--r--Source/cmFindPackageCommand.cxx1257
-rw-r--r--Source/cmFindPackageCommand.h2
-rw-r--r--Source/cmForEachCommand.cxx2
-rw-r--r--Source/cmFunctionBlocker.cxx18
-rw-r--r--Source/cmFunctionBlocker.h2
-rw-r--r--Source/cmFunctionCommand.cxx1
-rw-r--r--Source/cmGeneratedFileStream.cxx6
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.cxx10
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.h9
-rw-r--r--Source/cmGeneratorExpressionNode.cxx36
-rw-r--r--Source/cmGeneratorTarget.cxx56
-rw-r--r--Source/cmGeneratorTarget.h5
-rw-r--r--Source/cmGhsMultiTargetGenerator.cxx4
-rw-r--r--Source/cmGlobalGenerator.cxx118
-rw-r--r--Source/cmGlobalGenerator.h59
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx474
-rw-r--r--Source/cmGlobalNinjaGenerator.h4
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.cxx73
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.h5
-rw-r--r--Source/cmGlobalVisualStudio10Generator.cxx29
-rw-r--r--Source/cmGlobalVisualStudio10Generator.h5
-rw-r--r--Source/cmGlobalVisualStudio71Generator.cxx2
-rw-r--r--Source/cmGlobalVisualStudioGenerator.cxx6
-rw-r--r--Source/cmGlobalVisualStudioGenerator.h3
-rw-r--r--Source/cmGlobalVisualStudioVersionedGenerator.cxx163
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx75
-rw-r--r--Source/cmIfCommand.cxx2
-rw-r--r--Source/cmInstallCommand.cxx157
-rw-r--r--Source/cmInstallCommandArguments.h5
-rw-r--r--Source/cmInstallCxxModuleBmiGenerator.cxx75
-rw-r--r--Source/cmInstallCxxModuleBmiGenerator.h52
-rw-r--r--Source/cmInstallExportGenerator.cxx76
-rw-r--r--Source/cmInstallExportGenerator.h8
-rw-r--r--Source/cmLinkLibrariesCommand.cxx2
-rw-r--r--Source/cmLinkLineDeviceComputer.cxx21
-rw-r--r--Source/cmLinkLineDeviceComputer.h1
-rw-r--r--Source/cmListFileCache.cxx11
-rw-r--r--Source/cmLocalGenerator.cxx67
-rw-r--r--Source/cmLocalGenerator.h13
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx37
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx3
-rw-r--r--Source/cmMacroCommand.cxx2
-rw-r--r--Source/cmMakefile.cxx122
-rw-r--r--Source/cmMakefile.h21
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx17
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx13
-rw-r--r--Source/cmMakefileTargetGenerator.cxx6
-rw-r--r--Source/cmMessageCommand.cxx65
-rw-r--r--Source/cmMessageType.h16
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx22
-rw-r--r--Source/cmNinjaTargetGenerator.cxx230
-rw-r--r--Source/cmParseArgumentsCommand.cxx17
-rw-r--r--Source/cmPolicies.h15
-rw-r--r--Source/cmQtAutoGenInitializer.cxx3
-rw-r--r--Source/cmQtAutoMocUic.cxx12
-rw-r--r--Source/cmReturnCommand.cxx44
-rw-r--r--Source/cmScanDepFormat.cxx37
-rw-r--r--Source/cmScanDepFormat.h5
-rw-r--r--Source/cmSetPropertyCommand.cxx4
-rw-r--r--Source/cmSourceGroup.cxx15
-rw-r--r--Source/cmSourceGroup.h6
-rw-r--r--Source/cmStandardLevelResolver.cxx35
-rw-r--r--Source/cmStateSnapshot.cxx19
-rw-r--r--Source/cmStringAlgorithms.cxx32
-rw-r--r--Source/cmStringAlgorithms.h10
-rw-r--r--Source/cmStringCommand.cxx2
-rw-r--r--Source/cmSystemTools.cxx296
-rw-r--r--Source/cmSystemTools.h72
-rw-r--r--Source/cmTarget.cxx166
-rw-r--r--Source/cmTarget.h12
-rw-r--r--Source/cmTargetCompileDefinitionsCommand.cxx4
-rw-r--r--Source/cmTargetExport.h2
-rw-r--r--Source/cmTargetIncludeDirectoriesCommand.cxx3
-rw-r--r--Source/cmTargetLinkLibrariesCommand.cxx11
-rw-r--r--Source/cmTargetPrecompileHeadersCommand.cxx4
-rw-r--r--Source/cmTargetSourcesCommand.cxx19
-rw-r--r--Source/cmTryCompileCommand.cxx61
-rw-r--r--Source/cmTryCompileCommand.h30
-rw-r--r--Source/cmTryRunCommand.cxx341
-rw-r--r--Source/cmTryRunCommand.h44
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx290
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h11
-rw-r--r--Source/cmWhileCommand.cxx2
-rw-r--r--Source/cmWindowsRegistry.h2
-rw-r--r--Source/cmXCodeScheme.cxx24
-rw-r--r--Source/cmake.cxx99
-rw-r--r--Source/cmake.h29
-rw-r--r--Source/cmake.version.manifest2
-rw-r--r--Source/cmakemain.cxx19
-rw-r--r--Source/cmcldeps.cxx1
-rw-r--r--Source/cmcmd.cxx51
-rw-r--r--Source/kwsys/Directory.cxx39
-rw-r--r--Source/kwsys/SystemTools.cxx63
164 files changed, 7747 insertions, 3714 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 6312e93..32bd341 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -4,7 +4,7 @@
# To ensure maximum portability across various compilers and platforms
# deactivate any compiler extensions. Skip this for QNX, where additional
# work is needed to build without compiler extensions.
-if (NOT CMAKE_SYSTEM_NAME STREQUAL "QNX")
+if(NOT CMAKE_SYSTEM_NAME STREQUAL "QNX")
set(CMAKE_C_EXTENSIONS FALSE)
set(CMAKE_CXX_EXTENSIONS FALSE)
endif()
@@ -31,70 +31,48 @@ if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
set(CMake_USE_XCOFF_PARSER 1)
endif()
+# Watcom support
+if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ set(CMAKE_USE_WMAKE 1)
+endif()
+
+set(CMake_STAT_HAS_ST_MTIM ${KWSYS_CXX_STAT_HAS_ST_MTIM_COMPILED})
+set(CMake_STAT_HAS_ST_MTIMESPEC ${KWSYS_CXX_STAT_HAS_ST_MTIMESPEC_COMPILED})
+
set(EXECUTABLE_OUTPUT_PATH ${CMake_BIN_DIR})
if(WIN32)
# ensure Unicode friendly APIs are used on Windows
- add_definitions(-DUNICODE -D_UNICODE)
+ add_compile_definitions(UNICODE _UNICODE)
# minimize windows.h content
- add_definitions(-DWIN32_LEAN_AND_MEAN)
+ add_compile_definitions(WIN32_LEAN_AND_MEAN)
endif()
# configure the .dox.in file
if(CMake_BUILD_DEVELOPER_REFERENCE)
- configure_file(
- "${CMake_SOURCE_DIR}/Source/dir.dox.in"
- "${CMake_BINARY_DIR}/Source/dir.dox"
- @ONLY
- )
+ configure_file(dir.dox.in dir.dox @ONLY)
endif()
# configure the .h file
-configure_file(
- "${CMake_SOURCE_DIR}/Source/cmConfigure.cmake.h.in"
- "${CMake_BINARY_DIR}/Source/cmConfigure.h"
- )
-configure_file(
- "${CMake_SOURCE_DIR}/Source/cmVersionConfig.h.in"
- "${CMake_BINARY_DIR}/Source/cmVersionConfig.h"
- )
-configure_file(
- "${CMake_SOURCE_DIR}/Source/CPack/cmCPackConfigure.h.in"
- "${CMake_BINARY_DIR}/Source/CPack/cmCPackConfigure.h"
- )
+configure_file(cmConfigure.cmake.h.in cmConfigure.h)
+configure_file(cmVersionConfig.h.in cmVersionConfig.h)
# Tell CMake executable in the build tree where to find the source tree.
configure_file(
- "${CMake_SOURCE_DIR}/Source/CMakeSourceDir.txt.in"
- "${CMake_BINARY_DIR}/CMakeFiles/CMakeSourceDir.txt" @ONLY
- )
-
-# add the include path to find the .h
-include_directories(
- "${CMake_BINARY_DIR}/Source"
- "${CMake_SOURCE_DIR}/Source"
- "${CMake_SOURCE_DIR}/Source/LexerParser"
- ${CMAKE_ZLIB_INCLUDES}
- ${CMAKE_EXPAT_INCLUDES}
- ${CMAKE_TAR_INCLUDES}
- ${CMake_HAIKU_INCLUDE_DIRS}
+ CMakeSourceDir.txt.in
+ "${CMake_BINARY_DIR}/CMakeFiles/CMakeSourceDir.txt"
+ @ONLY
)
-# Check if we can build the Mach-O parser.
-if(CMake_USE_MACH_PARSER)
- set(MACH_SRCS cmMachO.h cmMachO.cxx)
-endif()
-
-# Check if we can build the XCOFF parser.
-if(CMake_USE_XCOFF_PARSER)
- set(XCOFF_SRCS cmXCOFF.h cmXCOFF.cxx)
-endif()
+# Add a dummy library and add sources later depends on condition
+add_library(ManifestLib INTERFACE)
#
-# Sources for CMakeLib
+# create a library used by the command line and the GUI
#
-set(SRCS
+add_library(
+ CMakeLib
# Lexers/Parsers
LexerParser/cmCommandArgumentLexer.cxx
LexerParser/cmCommandArgumentLexer.h
@@ -168,6 +146,7 @@ set(SRCS
cmCMakePresetsGraphReadJSON.cxx
cmCMakePresetsGraphReadJSONBuildPresets.cxx
cmCMakePresetsGraphReadJSONConfigurePresets.cxx
+ cmCMakePresetsGraphReadJSONPackagePresets.cxx
cmCMakePresetsGraphReadJSONTestPresets.cxx
cmCommandArgumentParserHelper.cxx
cmCommonTargetGenerator.cxx
@@ -369,7 +348,6 @@ set(SRCS
cmRulePlaceholderExpander.h
cmLocalUnixMakefileGenerator3.cxx
cmLocale.h
- ${MACH_SRCS}
cmMakefile.cxx
cmMakefile.h
cmMakefileTargetGenerator.cxx
@@ -469,7 +447,6 @@ set(SRCS
cmWorkerPool.h
cmWorkingDirectory.cxx
cmWorkingDirectory.h
- ${XCOFF_SRCS}
cmXMLParser.cxx
cmXMLParser.h
cmXMLSafe.cxx
@@ -571,6 +548,8 @@ set(SRCS
cmFindProgramCommand.h
cmForEachCommand.cxx
cmForEachCommand.h
+ cmBlockCommand.cxx
+ cmBlockCommand.h
cmFunctionBlocker.cxx
cmFunctionBlocker.h
cmFunctionCommand.cxx
@@ -607,6 +586,8 @@ set(SRCS
cmInstallCommand.h
cmInstallCommandArguments.cxx
cmInstallCommandArguments.h
+ cmInstallCxxModuleBmiGenerator.cxx
+ cmInstallCxxModuleBmiGenerator.h
cmInstallFilesCommand.cxx
cmInstallFilesCommand.h
cmInstallProgramsCommand.cxx
@@ -725,6 +706,23 @@ set(SRCS
cmWhileCommand.h
cmWriteFileCommand.cxx
cmWriteFileCommand.h
+ # Ninja support
+ cmScanDepFormat.cxx
+ cmGlobalNinjaGenerator.cxx
+ cmGlobalNinjaGenerator.h
+ cmNinjaTypes.h
+ cmLocalNinjaGenerator.cxx
+ cmLocalNinjaGenerator.h
+ cmNinjaTargetGenerator.cxx
+ cmNinjaTargetGenerator.h
+ cmNinjaNormalTargetGenerator.cxx
+ cmNinjaNormalTargetGenerator.h
+ cmNinjaUtilityTargetGenerator.cxx
+ cmNinjaUtilityTargetGenerator.h
+ cmNinjaLinkLineComputer.cxx
+ cmNinjaLinkLineComputer.h
+ cmNinjaLinkLineDeviceComputer.cxx
+ cmNinjaLinkLineDeviceComputer.h
cm_get_date.h
cm_get_date.c
@@ -738,102 +736,152 @@ set(SRCS
bindexplib.cxx
)
+target_include_directories(
+ CMakeLib
+ PUBLIC
+ # add the include path to find the .h
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/LexerParser"
+ ${CMake_HAIKU_INCLUDE_DIRS}
+ )
+target_link_libraries(
+ CMakeLib
+ PUBLIC
+ cmstd
+ cmsys
+ CURL::libcurl
+ EXPAT::EXPAT
+ JsonCpp::JsonCpp
+ $<TARGET_NAME_IF_EXISTS:kwiml::kwiml>
+ LibArchive::LibArchive
+ LibRHash::LibRHash
+ LibUV::LibUV
+ Threads::Threads
+ ZLIB::ZLIB
+ )
-SET_PROPERTY(SOURCE cmProcessOutput.cxx cmWindowsRegistry.cxx APPEND PROPERTY COMPILE_DEFINITIONS
- KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
+# Check if we can build the Mach-O parser.
+if(CMake_USE_MACH_PARSER)
+ target_sources(
+ CMakeLib
+ PUBLIC
+ cmMachO.h
+ cmMachO.cxx
+ )
+endif()
+
+# Check if we can build the XCOFF parser.
+if(CMake_USE_XCOFF_PARSER)
+ target_sources(
+ CMakeLib
+ PUBLIC
+ cmXCOFF.h
+ cmXCOFF.cxx
+ )
+endif()
# Xcode only works on Apple
if(APPLE)
- set(SRCS ${SRCS}
- cmXCodeObject.cxx
- cmXCode21Object.cxx
- cmXCodeScheme.cxx
- cmGlobalXCodeGenerator.cxx
- cmGlobalXCodeGenerator.h
- cmLocalXCodeGenerator.cxx
- cmLocalXCodeGenerator.h)
+ target_sources(
+ CMakeLib
+ PUBLIC
+ cmXCodeObject.cxx
+ cmXCode21Object.cxx
+ cmXCodeScheme.cxx
+ cmGlobalXCodeGenerator.cxx
+ cmGlobalXCodeGenerator.h
+ cmLocalXCodeGenerator.cxx
+ cmLocalXCodeGenerator.h
+ )
endif()
-
-if (WIN32)
- set(SRCS ${SRCS}
- cmCallVisualStudioMacro.cxx
- cmCallVisualStudioMacro.h
+if(WIN32)
+ target_sources(
+ CMakeLib
+ PUBLIC
+ cmCallVisualStudioMacro.cxx
+ cmCallVisualStudioMacro.h
)
if(NOT UNIX)
- set(SRCS ${SRCS}
- cmGlobalBorlandMakefileGenerator.cxx
- cmGlobalBorlandMakefileGenerator.h
- cmGlobalMSYSMakefileGenerator.cxx
- cmGlobalMinGWMakefileGenerator.cxx
- cmGlobalNMakeMakefileGenerator.cxx
- cmGlobalNMakeMakefileGenerator.h
- cmGlobalJOMMakefileGenerator.cxx
- cmGlobalJOMMakefileGenerator.h
- cmGlobalVisualStudio71Generator.cxx
- cmGlobalVisualStudio71Generator.h
- cmGlobalVisualStudio7Generator.cxx
- cmGlobalVisualStudio7Generator.h
- cmGlobalVisualStudio8Generator.cxx
- cmGlobalVisualStudio8Generator.h
- cmGlobalVisualStudio9Generator.cxx
- cmGlobalVisualStudio9Generator.h
- cmVisualStudioGeneratorOptions.h
- cmVisualStudioGeneratorOptions.cxx
- cmVsProjectType.h
- cmVisualStudio10TargetGenerator.h
- cmVisualStudio10TargetGenerator.cxx
- cmLocalVisualStudio10Generator.cxx
- cmLocalVisualStudio10Generator.h
- cmGlobalVisualStudio10Generator.h
- cmGlobalVisualStudio10Generator.cxx
- cmGlobalVisualStudio11Generator.h
- cmGlobalVisualStudio11Generator.cxx
- cmGlobalVisualStudio12Generator.h
- cmGlobalVisualStudio12Generator.cxx
- cmGlobalVisualStudio14Generator.h
- cmGlobalVisualStudio14Generator.cxx
- cmGlobalVisualStudioGenerator.cxx
- cmGlobalVisualStudioGenerator.h
- cmGlobalVisualStudioVersionedGenerator.h
- cmGlobalVisualStudioVersionedGenerator.cxx
- cmIDEFlagTable.h
- cmIDEOptions.cxx
- cmIDEOptions.h
- cmLocalVisualStudio7Generator.cxx
- cmLocalVisualStudio7Generator.h
- cmLocalVisualStudioGenerator.cxx
- cmLocalVisualStudioGenerator.h
- cmVisualStudioSlnData.h
- cmVisualStudioSlnData.cxx
- cmVisualStudioSlnParser.h
- cmVisualStudioSlnParser.cxx
- cmVisualStudioWCEPlatformParser.h
- cmVisualStudioWCEPlatformParser.cxx
- cmVSSetupHelper.cxx
- cmVSSetupHelper.h
+ target_sources(
+ CMakeLib
+ PUBLIC
+ cmGlobalBorlandMakefileGenerator.cxx
+ cmGlobalBorlandMakefileGenerator.h
+ cmGlobalMSYSMakefileGenerator.cxx
+ cmGlobalMinGWMakefileGenerator.cxx
+ cmGlobalNMakeMakefileGenerator.cxx
+ cmGlobalNMakeMakefileGenerator.h
+ cmGlobalJOMMakefileGenerator.cxx
+ cmGlobalJOMMakefileGenerator.h
+ cmGlobalVisualStudio71Generator.cxx
+ cmGlobalVisualStudio71Generator.h
+ cmGlobalVisualStudio7Generator.cxx
+ cmGlobalVisualStudio7Generator.h
+ cmGlobalVisualStudio8Generator.cxx
+ cmGlobalVisualStudio8Generator.h
+ cmGlobalVisualStudio9Generator.cxx
+ cmGlobalVisualStudio9Generator.h
+ cmVisualStudioGeneratorOptions.h
+ cmVisualStudioGeneratorOptions.cxx
+ cmVsProjectType.h
+ cmVisualStudio10TargetGenerator.h
+ cmVisualStudio10TargetGenerator.cxx
+ cmLocalVisualStudio10Generator.cxx
+ cmLocalVisualStudio10Generator.h
+ cmGlobalVisualStudio10Generator.h
+ cmGlobalVisualStudio10Generator.cxx
+ cmGlobalVisualStudio11Generator.h
+ cmGlobalVisualStudio11Generator.cxx
+ cmGlobalVisualStudio12Generator.h
+ cmGlobalVisualStudio12Generator.cxx
+ cmGlobalVisualStudio14Generator.h
+ cmGlobalVisualStudio14Generator.cxx
+ cmGlobalVisualStudioGenerator.cxx
+ cmGlobalVisualStudioGenerator.h
+ cmGlobalVisualStudioVersionedGenerator.h
+ cmGlobalVisualStudioVersionedGenerator.cxx
+ cmIDEFlagTable.h
+ cmIDEOptions.cxx
+ cmIDEOptions.h
+ cmLocalVisualStudio7Generator.cxx
+ cmLocalVisualStudio7Generator.h
+ cmLocalVisualStudioGenerator.cxx
+ cmLocalVisualStudioGenerator.h
+ cmVisualStudioSlnData.h
+ cmVisualStudioSlnData.cxx
+ cmVisualStudioSlnParser.h
+ cmVisualStudioSlnParser.cxx
+ cmVisualStudioWCEPlatformParser.h
+ cmVisualStudioWCEPlatformParser.cxx
+ cmVSSetupHelper.cxx
+ cmVSSetupHelper.h
)
# Add a manifest file to executables on Windows to allow for
# GetVersion to work properly on Windows 8 and above.
- set(MANIFEST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake.version.manifest)
+ target_sources(ManifestLib INTERFACE cmake.version.manifest)
endif()
-endif ()
+endif()
# Watcom support
-if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Darwin")
- set_property(SOURCE cmake.cxx APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_USE_WMAKE)
- list(APPEND SRCS
- cmGlobalWatcomWMakeGenerator.cxx
- cmGlobalWatcomWMakeGenerator.h
+if(CMAKE_USE_WMAKE)
+ target_sources(
+ CMakeLib
+ PUBLIC
+ cmGlobalWatcomWMakeGenerator.cxx
+ cmGlobalWatcomWMakeGenerator.h
)
endif()
# GHS support
# Works only for windows and linux
if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
- set(SRCS ${SRCS}
+ target_sources(
+ CMakeLib
+ PUBLIC
cmGlobalGhsMultiGenerator.cxx
cmGlobalGhsMultiGenerator.h
cmLocalGhsMultiGenerator.cxx
@@ -845,104 +893,45 @@ if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
)
endif()
-
-# Ninja support
-set(SRCS ${SRCS}
- cmScanDepFormat.cxx
- cmGlobalNinjaGenerator.cxx
- cmGlobalNinjaGenerator.h
- cmNinjaTypes.h
- cmLocalNinjaGenerator.cxx
- cmLocalNinjaGenerator.h
- cmNinjaTargetGenerator.cxx
- cmNinjaTargetGenerator.h
- cmNinjaNormalTargetGenerator.cxx
- cmNinjaNormalTargetGenerator.h
- cmNinjaUtilityTargetGenerator.cxx
- cmNinjaUtilityTargetGenerator.h
- cmNinjaLinkLineComputer.cxx
- cmNinjaLinkLineComputer.h
- cmNinjaLinkLineDeviceComputer.cxx
- cmNinjaLinkLineDeviceComputer.h
- )
-
# Temporary variable for tools targets
set(_tools)
if(WIN32 AND NOT CYGWIN)
set_source_files_properties(cmcldeps.cxx PROPERTIES COMPILE_DEFINITIONS _WIN32_WINNT=0x0501)
- add_executable(cmcldeps cmcldeps.cxx ${MANIFEST_FILE})
+ add_executable(cmcldeps cmcldeps.cxx)
+ target_link_libraries(cmcldeps PRIVATE CMakeLib ManifestLib)
list(APPEND _tools cmcldeps)
- target_link_libraries(cmcldeps CMakeLib)
endif()
-foreach(v CURL_CA_BUNDLE CURL_CA_PATH)
- if(${v})
- set_property(SOURCE cmCurl.cxx APPEND PROPERTY COMPILE_DEFINITIONS ${v}="${${v}}")
- endif()
-endforeach()
-
-foreach(check
- STAT_HAS_ST_MTIM
- STAT_HAS_ST_MTIMESPEC
- )
- if(KWSYS_CXX_${check}_COMPILED) # abuse KWSys check cache entry
- set(CMake_${check} 1)
- else()
- set(CMake_${check} 0)
- endif()
- set_property(SOURCE cmFileTime.cxx APPEND PROPERTY
- COMPILE_DEFINITIONS CMake_${check}=${CMake_${check}})
-endforeach()
-
-# create a library used by the command line and the GUI
-add_library(CMakeLib ${SRCS})
-target_link_libraries(CMakeLib cmsys
- ${CMAKE_STD_LIBRARY}
- ${CMAKE_EXPAT_LIBRARIES} ${CMAKE_ZLIB_LIBRARIES}
- ${CMAKE_TAR_LIBRARIES}
- ${CMAKE_CURL_LIBRARIES}
- ${CMAKE_JSONCPP_LIBRARIES}
- ${CMAKE_LIBUV_LIBRARIES}
- ${CMAKE_LIBRHASH_LIBRARIES}
- ${CMake_KWIML_LIBRARIES}
- ${CMAKE_THREAD_LIBS_INIT}
- )
-
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "sparc")
# the atomic instructions are implemented using libatomic on some platforms,
# so linking to that may be required
check_library_exists(atomic __atomic_fetch_add_4 "" LIBATOMIC_NEEDED)
if(LIBATOMIC_NEEDED)
- target_link_libraries(CMakeLib atomic)
+ target_link_libraries(CMakeLib PUBLIC atomic)
endif()
endif()
# On Apple we need CoreFoundation and CoreServices
if(APPLE)
- target_link_libraries(CMakeLib "-framework CoreFoundation")
- target_link_libraries(CMakeLib "-framework CoreServices")
+ target_link_libraries(CMakeLib PUBLIC "-framework CoreFoundation")
+ target_link_libraries(CMakeLib PUBLIC "-framework CoreServices")
endif()
if(WIN32 AND NOT UNIX)
# We need the rpcrt4 library on Windows.
# We need the crypt32 library on Windows for crypto/cert APIs.
- target_link_libraries(CMakeLib rpcrt4 crypt32)
+ target_link_libraries(CMakeLib PUBLIC rpcrt4 crypt32)
endif()
target_compile_definitions(CMakeLib PUBLIC ${CLANG_TIDY_DEFINITIONS})
#
-# CTestLib
-#
-include_directories(
- "${CMake_SOURCE_DIR}/Source/CTest"
- ${CMAKE_CURL_INCLUDES}
- )
-#
-# Sources for CTestLib
+# Build CTestLib
#
-set(CTEST_SRCS cmCTest.cxx
+add_library(
+ CTestLib
+ cmCTest.cxx
CTest/cmProcess.cxx
CTest/cmCTestBinPacker.cxx
CTest/cmCTestBuildAndTestHandler.cxx
@@ -1009,21 +998,18 @@ set(CTEST_SRCS cmCTest.cxx
LexerParser/cmCTestResourceGroupsLexer.h
LexerParser/cmCTestResourceGroupsLexer.in.l
)
-
-# Build CTestLib
-add_library(CTestLib ${CTEST_SRCS})
-target_link_libraries(CTestLib CMakeLib ${CMAKE_CURL_LIBRARIES})
-
-#
-# CPack
-#
-include_directories(
- "${CMake_SOURCE_DIR}/Source/CPack"
+target_include_directories(
+ CTestLib
+ PUBLIC
+ "${CMAKE_CURRENT_SOURCE_DIR}/CTest"
)
+target_link_libraries(CTestLib PUBLIC CMakeLib)
+
#
-# Sources for CPack
+# Build CPackLib
#
-set(CPACK_SRCS
+add_library(
+ CPackLib
CPack/cmCPackArchiveGenerator.cxx
CPack/cmCPackComponentGroup.cxx
CPack/cmCPackDebGenerator.cxx
@@ -1034,9 +1020,7 @@ set(CPACK_SRCS
CPack/cmCPackNSISGenerator.cxx
CPack/cmCPackNuGetGenerator.cxx
CPack/cmCPackSTGZGenerator.cxx
- )
-# CPack IFW generator
-set(CPACK_SRCS ${CPACK_SRCS}
+ # CPack IFW generator
CPack/IFW/cmCPackIFWCommon.cxx
CPack/IFW/cmCPackIFWCommon.h
CPack/IFW/cmCPackIFWGenerator.cxx
@@ -1048,19 +1032,20 @@ set(CPACK_SRCS ${CPACK_SRCS}
CPack/IFW/cmCPackIFWRepository.cxx
CPack/IFW/cmCPackIFWRepository.h
)
-
-if(CYGWIN)
- set(CPACK_SRCS ${CPACK_SRCS}
- CPack/cmCPackCygwinBinaryGenerator.cxx
- CPack/cmCPackCygwinSourceGenerator.cxx
- )
-endif()
+target_include_directories(
+ CPackLib
+ PUBLIC
+ "${CMAKE_CURRENT_SOURCE_DIR}/CPack"
+ "${CMAKE_CURRENT_BINARY_DIR}/CPack"
+ )
+target_link_libraries(CPackLib PUBLIC CMakeLib)
option(CPACK_ENABLE_FREEBSD_PKG "Add FreeBSD pkg(8) generator to CPack." OFF)
-
if(UNIX)
- set(CPACK_SRCS ${CPACK_SRCS}
- CPack/cmCPackRPMGenerator.cxx
+ target_sources(
+ CPackLib
+ PUBLIC
+ CPack/cmCPackRPMGenerator.cxx
)
# Optionally, try to use pkg(8)
@@ -1076,13 +1061,14 @@ if(UNIX)
pkg
DOC "FreeBSD pkg(8) library")
if(FREEBSD_PKG_LIBRARIES)
- set(CPACK_SRCS ${CPACK_SRCS}
- CPack/cmCPackFreeBSDGenerator.cxx
- )
+ set(ENABLE_BUILD_FREEBSD_PKG 1)
+ target_sources(CPackLib PUBLIC CPack/cmCPackFreeBSDGenerator.cxx)
+ target_include_directories(CPackLib PUBLIC ${FREEBSD_PKG_INCLUDE_DIRS})
+ target_link_libraries(CPackLib PUBLIC ${FREEBSD_PKG_LIBRARIES})
endif()
endif()
- if (NOT FREEBSD_PKG_INCLUDE_DIRS OR NOT FREEBSD_PKG_LIBRARIES)
+ if(NOT FREEBSD_PKG_INCLUDE_DIRS OR NOT FREEBSD_PKG_LIBRARIES)
message(FATAL_ERROR "CPack needs libpkg(3) to produce FreeBSD packages natively.")
endif()
else()
@@ -1092,47 +1078,57 @@ if(UNIX)
endif()
if(CYGWIN)
+ target_sources(
+ CPackLib
+ PUBLIC
+ CPack/cmCPackCygwinBinaryGenerator.cxx
+ CPack/cmCPackCygwinSourceGenerator.cxx
+ )
find_package(LibUUID)
endif()
-if(WIN32 OR (CYGWIN AND LibUUID_FOUND))
- set(CPACK_SRCS ${CPACK_SRCS}
- CPack/WiX/cmCMakeToWixPath.cxx
- CPack/WiX/cmCMakeToWixPath.h
- CPack/WiX/cmCPackWIXGenerator.cxx
- CPack/WiX/cmCPackWIXGenerator.h
- CPack/WiX/cmWIXAccessControlList.cxx
- CPack/WiX/cmWIXAccessControlList.h
- CPack/WiX/cmWIXDirectoriesSourceWriter.cxx
- CPack/WiX/cmWIXDirectoriesSourceWriter.h
- CPack/WiX/cmWIXFeaturesSourceWriter.cxx
- CPack/WiX/cmWIXFeaturesSourceWriter.h
- CPack/WiX/cmWIXFilesSourceWriter.cxx
- CPack/WiX/cmWIXFilesSourceWriter.h
- CPack/WiX/cmWIXPatch.cxx
- CPack/WiX/cmWIXPatch.h
- CPack/WiX/cmWIXPatchParser.cxx
- CPack/WiX/cmWIXPatchParser.h
- CPack/WiX/cmWIXRichTextFormatWriter.cxx
- CPack/WiX/cmWIXRichTextFormatWriter.h
- CPack/WiX/cmWIXShortcut.cxx
- CPack/WiX/cmWIXShortcut.h
- CPack/WiX/cmWIXSourceWriter.cxx
- CPack/WiX/cmWIXSourceWriter.h
+
+if(WIN32 OR (CYGWIN AND TARGET LibUUID::LibUUID))
+ set(ENABLE_BUILD_WIX_GENERATOR 1)
+ target_sources(
+ CPackLib
+ PUBLIC
+ CPack/WiX/cmCMakeToWixPath.cxx
+ CPack/WiX/cmCMakeToWixPath.h
+ CPack/WiX/cmCPackWIXGenerator.cxx
+ CPack/WiX/cmCPackWIXGenerator.h
+ CPack/WiX/cmWIXAccessControlList.cxx
+ CPack/WiX/cmWIXAccessControlList.h
+ CPack/WiX/cmWIXDirectoriesSourceWriter.cxx
+ CPack/WiX/cmWIXDirectoriesSourceWriter.h
+ CPack/WiX/cmWIXFeaturesSourceWriter.cxx
+ CPack/WiX/cmWIXFeaturesSourceWriter.h
+ CPack/WiX/cmWIXFilesSourceWriter.cxx
+ CPack/WiX/cmWIXFilesSourceWriter.h
+ CPack/WiX/cmWIXPatch.cxx
+ CPack/WiX/cmWIXPatch.h
+ CPack/WiX/cmWIXPatchParser.cxx
+ CPack/WiX/cmWIXPatchParser.h
+ CPack/WiX/cmWIXRichTextFormatWriter.cxx
+ CPack/WiX/cmWIXRichTextFormatWriter.h
+ CPack/WiX/cmWIXShortcut.cxx
+ CPack/WiX/cmWIXShortcut.h
+ CPack/WiX/cmWIXSourceWriter.cxx
+ CPack/WiX/cmWIXSourceWriter.h
)
+ target_link_libraries(CPackLib PUBLIC $<TARGET_NAME_IF_EXISTS:LibUUID::LibUUID>)
endif()
if(APPLE)
- set(CPACK_SRCS ${CPACK_SRCS}
- CPack/cmCPackBundleGenerator.cxx
- CPack/cmCPackDragNDropGenerator.cxx
- CPack/cmCPackPKGGenerator.cxx
- CPack/cmCPackProductBuildGenerator.cxx
+ target_sources(
+ CPackLib
+ PUBLIC
+ CPack/cmCPackBundleGenerator.cxx
+ CPack/cmCPackDragNDropGenerator.cxx
+ CPack/cmCPackPKGGenerator.cxx
+ CPack/cmCPackProductBuildGenerator.cxx
)
endif()
-# Build CPackLib
-add_library(CPackLib ${CPACK_SRCS})
-target_link_libraries(CPackLib CMakeLib)
if(APPLE)
# Some compilers produce errors in the CoreServices framework headers.
# Ideally such errors should be fixed by either the compiler vendor
@@ -1140,8 +1136,7 @@ if(APPLE)
# If it does not work, build with reduced functionality and warn.
check_include_file("CoreServices/CoreServices.h" HAVE_CoreServices)
if(HAVE_CoreServices)
- set_property(SOURCE CPack/cmCPackDragNDropGenerator.cxx PROPERTY COMPILE_DEFINITIONS HAVE_CoreServices)
- target_link_libraries(CPackLib "-framework CoreServices")
+ target_link_libraries(CPackLib PUBLIC "-framework CoreServices")
else()
message(WARNING "This compiler does not appear to support\n"
" #include <CoreServices/CoreServices.h>\n"
@@ -1149,31 +1144,25 @@ if(APPLE)
"See CMakeFiles/CMakeError.log for details of the failure.")
endif()
endif()
-if(CYGWIN AND LibUUID_FOUND)
- target_link_libraries(CPackLib ${LibUUID_LIBRARIES})
- include_directories(CPackLib ${LibUUID_INCLUDE_DIRS})
- set_property(SOURCE CPack/cmCPackGeneratorFactory.cxx PROPERTY COMPILE_DEFINITIONS HAVE_LIBUUID)
-endif()
-if(CPACK_ENABLE_FREEBSD_PKG AND FREEBSD_PKG_INCLUDE_DIRS AND FREEBSD_PKG_LIBRARIES)
- target_link_libraries(CPackLib ${FREEBSD_PKG_LIBRARIES})
- include_directories(${FREEBSD_PKG_INCLUDE_DIRS})
- add_definitions(-DHAVE_FREEBSD_PKG)
-endif()
+
+# Render config header file for CPackLib
+configure_file(CPack/cmCPackConfigure.h.in CPack/cmCPackConfigure.h)
+
# Build CMake executable
-add_executable(cmake cmakemain.cxx cmcmd.cxx cmcmd.h ${MANIFEST_FILE})
+add_executable(cmake cmakemain.cxx cmcmd.cxx cmcmd.h)
+target_link_libraries(cmake PRIVATE CMakeLib ManifestLib)
list(APPEND _tools cmake)
-target_link_libraries(cmake CMakeLib)
# Build CTest executable
-add_executable(ctest ctest.cxx ${MANIFEST_FILE})
+add_executable(ctest ctest.cxx)
+target_link_libraries(ctest PRIVATE CTestLib ManifestLib)
list(APPEND _tools ctest)
-target_link_libraries(ctest CTestLib)
# Build CPack executable
-add_executable(cpack CPack/cpack.cxx ${MANIFEST_FILE})
+add_executable(cpack CPack/cpack.cxx)
+target_link_libraries(cpack PRIVATE CPackLib ManifestLib)
list(APPEND _tools cpack)
-target_link_libraries(cpack CPackLib)
# Curses GUI
if(BUILD_CursesDialog)
@@ -1186,8 +1175,8 @@ if(BUILD_QtDialog)
add_subdirectory(QtDialog)
endif()
-include (${CMake_BINARY_DIR}/Source/LocalUserOptions.cmake OPTIONAL)
-include (${CMake_SOURCE_DIR}/Source/LocalUserOptions.cmake OPTIONAL)
+include(${CMAKE_CURRENT_BINARY_DIR}/LocalUserOptions.cmake OPTIONAL)
+include(${CMAKE_CURRENT_SOURCE_DIR}/LocalUserOptions.cmake OPTIONAL)
if(WIN32)
# Compute the binary version that appears in the RC file. Version
@@ -1206,14 +1195,14 @@ if(WIN32)
set(CMake_RCVERSION_STR ${CMake_VERSION})
# Add Windows executable version information.
- configure_file("CMakeVersion.rc.in" "CMakeVersion.rc" @ONLY)
+ configure_file(CMakeVersion.rc.in CMakeVersion.rc @ONLY)
# We use a separate object library for this to work around a limitation of
# MinGW's windres tool with spaces in the path to the include directories.
add_library(CMakeVersion OBJECT "${CMAKE_CURRENT_BINARY_DIR}/CMakeVersion.rc")
set_property(TARGET CMakeVersion PROPERTY INCLUDE_DIRECTORIES "")
- foreach(_tool ${_tools})
- target_sources(${_tool} PRIVATE $<TARGET_OBJECTS:CMakeVersion>)
+ foreach(_tool IN LISTS _tools)
+ target_link_libraries(${_tool} PRIVATE CMakeVersion)
endforeach()
endif()
@@ -1224,7 +1213,7 @@ endif()
# Install tools
-foreach(_tool ${_tools})
+foreach(_tool IN LISTS _tools)
CMake_OPTIONAL_COMPONENT(${_tool})
install(TARGETS ${_tool} DESTINATION ${CMAKE_BIN_DIR} ${COMPONENT})
endforeach()
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 5e99b47..b9c72f1 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 24)
-set(CMake_VERSION_PATCH 20220627)
+set(CMake_VERSION_PATCH 20220927)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
@@ -9,7 +9,7 @@ set(CMake_VERSION_IS_DIRTY 0)
set(CMake_VERSION
"${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}.${CMake_VERSION_PATCH}")
if(DEFINED CMake_VERSION_RC)
- set(CMake_VERSION "${CMake_VERSION}-rc${CMake_VERSION_RC}")
+ string(APPEND CMake_VERSION "-rc${CMake_VERSION_RC}")
endif()
# Releases define a small patch level.
@@ -53,7 +53,7 @@ if(NOT CMake_VERSION_NO_GIT)
# If this is not the exact commit of a release, add dev info.
if(NOT "${git_subject}" MATCHES "^[Cc][Mm]ake ${CMake_VERSION}$")
- set(CMake_VERSION "${CMake_VERSION}-g${git_hash}")
+ string(APPEND CMake_VERSION "-g${git_hash}")
endif()
# If this is a work tree, check whether it is dirty.
@@ -68,7 +68,7 @@ if(NOT CMake_VERSION_NO_GIT)
# No commit information.
if(NOT CMake_VERSION_IS_RELEASE)
# Generic development version.
- set(CMake_VERSION "${CMake_VERSION}-git")
+ string(APPEND CMake_VERSION "-git")
endif()
endif()
endif()
@@ -80,5 +80,5 @@ else()
set(CMake_VERSION_SUFFIX "")
endif()
if(CMake_VERSION_IS_DIRTY)
- set(CMake_VERSION ${CMake_VERSION}-dirty)
+ string(APPEND CMake_VERSION "-dirty")
endif()
diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx
index 56e8463..894c24b 100644
--- a/Source/CPack/cmCPackArchiveGenerator.cxx
+++ b/Source/CPack/cmCPackArchiveGenerator.cxx
@@ -94,6 +94,18 @@ std::string cmCPackArchiveGenerator::GetArchiveComponentFileName(
int cmCPackArchiveGenerator::InitializeInternal()
{
this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1");
+ cmValue newExtensionValue = this->GetOption("CPACK_ARCHIVE_FILE_EXTENSION");
+ if (!newExtensionValue.IsEmpty()) {
+ std::string newExtension = *newExtensionValue;
+ if (!cmHasLiteralPrefix(newExtension, ".")) {
+ newExtension = cmStrCat('.', newExtension);
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "Using user-provided file extension "
+ << newExtension << " instead of the default "
+ << this->OutputExtension << std::endl);
+ this->OutputExtension = std::move(newExtension);
+ }
return this->Superclass::InitializeInternal();
}
diff --git a/Source/CPack/cmCPackConfigure.h.in b/Source/CPack/cmCPackConfigure.h.in
index 8ac1661..2c1302d 100644
--- a/Source/CPack/cmCPackConfigure.h.in
+++ b/Source/CPack/cmCPackConfigure.h.in
@@ -1,2 +1,7 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#cmakedefine01 ENABLE_BUILD_WIX_GENERATOR
+#cmakedefine01 ENABLE_BUILD_FREEBSD_PKG
+#cmakedefine01 HAVE_CoreServices
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
index 0f7acfb..0579066 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.cxx
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -14,6 +14,7 @@
#include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
+#include "cmCPackConfigure.h"
#include "cmCPackGenerator.h"
#include "cmCPackLog.h"
#include "cmDuration.h"
@@ -23,7 +24,7 @@
#include "cmValue.h"
#include "cmXMLWriter.h"
-#ifdef HAVE_CoreServices
+#if HAVE_CoreServices
// For the old LocaleStringToLangAndRegionCodes() function, to convert
// to the old Script Manager RegionCode values needed for the 'LPic' data
// structure used for generating multi-lingual SLAs.
@@ -590,7 +591,7 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
kCFStringEncodingMacRoman);
LangCode lang = 0;
RegionCode region = 0;
-#ifdef HAVE_CoreServices
+#if HAVE_CoreServices
OSStatus err =
LocaleStringToLangAndRegionCodes(iso_language_cstr, &lang, &region);
if (err != noErr)
@@ -601,7 +602,7 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
<< iso_language_cstr << std::endl);
return 0;
}
-#ifdef HAVE_CoreServices
+#if HAVE_CoreServices
header_data.push_back(region);
header_data.push_back(i);
header_data.push_back(0);
diff --git a/Source/CPack/cmCPackFreeBSDGenerator.cxx b/Source/CPack/cmCPackFreeBSDGenerator.cxx
index 607d797..162dfc7 100644
--- a/Source/CPack/cmCPackFreeBSDGenerator.cxx
+++ b/Source/CPack/cmCPackFreeBSDGenerator.cxx
@@ -23,8 +23,6 @@
// Suffix used to tell libpkg what compression to use
static const char FreeBSDPackageCompression[] = "txz";
-// Resulting package file-suffix, for < 1.17 and >= 1.17 versions of libpkg
-static const char FreeBSDPackageSuffix_10[] = ".txz";
static const char FreeBSDPackageSuffix_17[] = ".pkg";
cmCPackFreeBSDGenerator::cmCPackFreeBSDGenerator()
@@ -83,6 +81,14 @@ public:
{
if (!isValid())
return false;
+ // The API in the FreeBSD sources (the header has no documentation),
+ // is as follows:
+ //
+ // int pkg_create(struct pkg_create *pc, const char *metadata, const char
+ // *plist, bool hash)
+ //
+ // We let the plist be determined from what is installed, and all
+ // the rest comes from the manifest data.
int r = pkg_create(d, manifest.c_str(), nullptr, false);
return r == 0;
}
@@ -402,7 +408,8 @@ int cmCPackFreeBSDGenerator::PackageFiles()
return 0;
}
- std::string output_dir = cmSystemTools::CollapseFullPath("../", toplevel);
+ const std::string output_dir =
+ cmSystemTools::CollapseFullPath("../", toplevel);
PkgCreate package(output_dir, toplevel, manifestname);
if (package.isValid()) {
if (!package.Create()) {
@@ -416,40 +423,33 @@ int cmCPackFreeBSDGenerator::PackageFiles()
return 0;
}
- // Specifically looking for packages suffixed with the TAG, either extension
- std::string broken_suffix_10 =
- cmStrCat('-', var_lookup("CPACK_TOPLEVEL_TAG"), FreeBSDPackageSuffix_10);
+ // Specifically looking for packages suffixed with the TAG
std::string broken_suffix_17 =
cmStrCat('-', var_lookup("CPACK_TOPLEVEL_TAG"), FreeBSDPackageSuffix_17);
for (std::string& name : packageFileNames) {
cmCPackLogger(cmCPackLog::LOG_DEBUG, "Packagefile " << name << std::endl);
- if (cmHasSuffix(name, broken_suffix_10)) {
- name.replace(name.size() - broken_suffix_10.size(), std::string::npos,
- FreeBSDPackageSuffix_10);
- break;
- }
if (cmHasSuffix(name, broken_suffix_17)) {
name.replace(name.size() - broken_suffix_17.size(), std::string::npos,
FreeBSDPackageSuffix_17);
break;
}
}
- // If the name uses a *new* style name, which doesn't exist, but there
- // is an *old* style name, then use that instead. This indicates we used
- // an older libpkg, which still creates .txz instead of .pkg files.
- for (std::string& name : packageFileNames) {
- if (cmHasSuffix(name, FreeBSDPackageSuffix_17) &&
- !cmSystemTools::FileExists(name)) {
- const std::string badSuffix(FreeBSDPackageSuffix_17);
- const std::string goodSuffix(FreeBSDPackageSuffix_10);
- std::string repairedName(name);
- repairedName.replace(repairedName.size() - badSuffix.size(),
- std::string::npos, goodSuffix);
- if (cmSystemTools::FileExists(repairedName)) {
- name = repairedName;
- cmCPackLogger(cmCPackLog::LOG_DEBUG,
- "Repaired packagefile " << name << std::endl);
- }
+
+ const std::string packageFileName =
+ var_lookup("CPACK_PACKAGE_FILE_NAME") + FreeBSDPackageSuffix_17;
+ if (packageFileNames.size() == 1 && !packageFileName.empty() &&
+ packageFileNames[0] != packageFileName) {
+ // Since libpkg always writes <name>-<version>.<suffix>,
+ // if there is a CPACK_PACKAGE_FILE_NAME set, we need to
+ // rename, and then re-set the name.
+ const std::string sourceFile = packageFileNames[0];
+ const std::string packageSubDirectory =
+ cmSystemTools::GetParentDirectory(sourceFile);
+ const std::string targetFileName =
+ packageSubDirectory + '/' + packageFileName;
+ if (cmSystemTools::RenameFile(sourceFile, targetFileName)) {
+ this->packageFileNames.clear();
+ this->packageFileNames.emplace_back(targetFileName);
}
}
diff --git a/Source/CPack/cmCPackGeneratorFactory.cxx b/Source/CPack/cmCPackGeneratorFactory.cxx
index 725ea8a..efb94b9 100644
--- a/Source/CPack/cmCPackGeneratorFactory.cxx
+++ b/Source/CPack/cmCPackGeneratorFactory.cxx
@@ -6,7 +6,7 @@
#include <utility>
#include "IFW/cmCPackIFWGenerator.h"
-#ifdef HAVE_FREEBSD_PKG
+#if ENABLE_BUILD_FREEBSD_PKG
# include "cmCPackFreeBSDGenerator.h"
#endif
#include "cmCPackArchiveGenerator.h"
@@ -34,7 +34,7 @@
# include "cmCPackRPMGenerator.h"
#endif
-#if defined(_WIN32) || (defined(__CYGWIN__) && defined(HAVE_LIBUUID))
+#if ENABLE_BUILD_WIX_GENERATOR
# include "WiX/cmCPackWIXGenerator.h"
#endif
@@ -80,7 +80,7 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory()
cmCPackCygwinSourceGenerator::CreateGenerator);
}
#endif
-#if defined(_WIN32) || (defined(__CYGWIN__) && defined(HAVE_LIBUUID))
+#if ENABLE_BUILD_WIX_GENERATOR
if (cmCPackWIXGenerator::CanGenerate()) {
this->RegisterGenerator("WIX", "MSI file format via WiX tools",
cmCPackWIXGenerator::CreateGenerator);
@@ -119,7 +119,7 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory()
cmCPackRPMGenerator::CreateGenerator);
}
#endif
-#ifdef HAVE_FREEBSD_PKG
+#if ENABLE_BUILD_FREEBSD_PKG
if (cmCPackFreeBSDGenerator::CanGenerate()) {
this->RegisterGenerator("FREEBSD", "FreeBSD pkg(8) packages",
cmCPackFreeBSDGenerator::CreateGenerator);
diff --git a/Source/CPack/cmCPackGeneratorFactory.h b/Source/CPack/cmCPackGeneratorFactory.h
index f3e25a6..52c1b5c 100644
--- a/Source/CPack/cmCPackGeneratorFactory.h
+++ b/Source/CPack/cmCPackGeneratorFactory.h
@@ -8,6 +8,8 @@
#include <memory>
#include <string>
+#include "cmCPackConfigure.h" // IWYU pragma: keep
+
class cmCPackGenerator;
class cmCPackLog;
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
index 217f716..6ca5783 100644
--- a/Source/CPack/cmCPackNSISGenerator.cxx
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -242,6 +242,33 @@ int cmCPackNSISGenerator::PackageFiles()
this->SetOptionIfNotSet("CPACK_NSIS_LICENSE_PAGE", licenceCode);
}
+ std::string nsisPreArguments;
+ if (cmValue nsisArguments =
+ this->GetOption("CPACK_NSIS_EXECUTABLE_PRE_ARGUMENTS")) {
+ std::vector<std::string> expandedArguments;
+ cmExpandList(nsisArguments, expandedArguments);
+
+ for (auto& arg : expandedArguments) {
+ if (!cmHasPrefix(arg, NSIS_OPT)) {
+ nsisPreArguments = cmStrCat(nsisPreArguments, NSIS_OPT);
+ }
+ nsisPreArguments = cmStrCat(nsisPreArguments, arg, ' ');
+ }
+ }
+
+ std::string nsisPostArguments;
+ if (cmValue nsisArguments =
+ this->GetOption("CPACK_NSIS_EXECUTABLE_POST_ARGUMENTS")) {
+ std::vector<std::string> expandedArguments;
+ cmExpandList(nsisArguments, expandedArguments);
+ for (auto& arg : expandedArguments) {
+ if (!cmHasPrefix(arg, NSIS_OPT)) {
+ nsisPostArguments = cmStrCat(nsisPostArguments, NSIS_OPT);
+ }
+ nsisPostArguments = cmStrCat(nsisPostArguments, arg, ' ');
+ }
+ }
+
// Setup all of the component sections
if (this->Components.empty()) {
this->SetOptionIfNotSet("CPACK_NSIS_INSTALLATION_TYPES", "");
@@ -358,8 +385,11 @@ int cmCPackNSISGenerator::PackageFiles()
this->ConfigureFile(nsisInInstallOptions, nsisInstallOptions);
this->ConfigureFile(nsisInFileName, nsisFileName);
std::string nsisCmd =
- cmStrCat('"', this->GetOption("CPACK_INSTALLER_PROGRAM"), "\" \"",
- nsisFileName, '"');
+ cmStrCat('"', this->GetOption("CPACK_INSTALLER_PROGRAM"), "\" ",
+ nsisPreArguments, " \"", nsisFileName, '"');
+ if (!nsisPostArguments.empty()) {
+ nsisCmd = cmStrCat(nsisCmd, " ", nsisPostArguments);
+ }
cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << nsisCmd << std::endl);
std::string output;
int retVal = 1;
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index 221f7dd..631bfd9 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -1,6 +1,7 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
+#include <algorithm>
#include <cstddef>
#include <functional>
#include <iostream>
@@ -11,10 +12,12 @@
#include <utility>
#include <vector>
+#include <cm/optional>
#include <cmext/algorithm>
#include "cmsys/Encoding.hxx"
+#include "cmCMakePresetsGraph.h"
#include "cmCPackGenerator.h"
#include "cmCPackGeneratorFactory.h"
#include "cmCPackLog.h"
@@ -50,7 +53,7 @@ const char* cmDocumentationOptions[][2] = {
{ "-C <Configuration>", "Specify the project configuration" },
{ "-D <var>=<value>", "Set a CPack variable." },
{ "--config <configFile>", "Specify the config file." },
- { "--verbose,-V", "Enable verbose output" },
+ { "-V,--verbose", "Enable verbose output" },
{ "--trace", "Put underlying cmake scripts in trace mode." },
{ "--trace-expand", "Put underlying cmake scripts in expanded trace mode." },
{ "--debug", "Enable debug output (for CPack developers)" },
@@ -58,6 +61,8 @@ const char* cmDocumentationOptions[][2] = {
{ "-R <packageVersion>", "Override/define CPACK_PACKAGE_VERSION" },
{ "-B <packageDirectory>", "Override/define CPACK_PACKAGE_DIRECTORY" },
{ "--vendor <vendorName>", "Override/define CPACK_PACKAGE_VENDOR" },
+ { "--preset", "Read arguments from a package preset" },
+ { "--list-presets", "List available package presets" },
{ nullptr, nullptr }
};
@@ -116,6 +121,9 @@ int main(int argc, char const* const* argv)
std::string cpackProjectVendor;
std::string cpackConfigFile;
+ std::string preset;
+ bool listPresets = false;
+
std::map<std::string, std::string> definitions;
auto const verboseLambda = [&log](const std::string&, cmake*,
@@ -182,6 +190,10 @@ int main(int argc, char const* const* argv)
CommandArgument::setToValue(cpackProjectPatch) },
CommandArgument{ "--vendor", CommandArgument::Values::One,
CommandArgument::setToValue(cpackProjectVendor) },
+ CommandArgument{ "--preset", CommandArgument::Values::One,
+ CommandArgument::setToValue(preset) },
+ CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
+ CommandArgument::setToTrue(listPresets) },
CommandArgument{
"-D", CommandArgument::Values::One,
[&log, &definitions](const std::string& arg, cmake*,
@@ -228,6 +240,160 @@ int main(int argc, char const* const* argv)
}
}
+ cmCPackGeneratorFactory generators;
+ generators.SetLogger(&log);
+
+ // Set up presets
+ if (!preset.empty() || listPresets) {
+ const auto workingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
+
+ auto const presetGeneratorsPresent =
+ [&generators](const cmCMakePresetsGraph::PackagePreset& p) {
+ return std::all_of(p.Generators.begin(), p.Generators.end(),
+ [&generators](const std::string& gen) {
+ return generators.GetGeneratorsList().count(
+ gen) != 0;
+ });
+ };
+
+ cmCMakePresetsGraph presetsGraph;
+ auto result = presetsGraph.ReadProjectPresets(workingDirectory);
+ if (result != cmCMakePresetsGraph::ReadFileResult::READ_OK) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Could not read presets from "
+ << workingDirectory << ": "
+ << cmCMakePresetsGraph::ResultToString(result)
+ << std::endl);
+ return 1;
+ }
+
+ if (listPresets) {
+ presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
+ return 0;
+ }
+
+ auto presetPair = presetsGraph.PackagePresets.find(preset);
+ if (presetPair == presetsGraph.PackagePresets.end()) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "No such package preset in " << workingDirectory << ": \""
+ << preset << '"' << std::endl);
+ presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
+ return 1;
+ }
+
+ if (presetPair->second.Unexpanded.Hidden) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Cannot use hidden package preset in "
+ << workingDirectory << ": \"" << preset << '"'
+ << std::endl);
+ presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
+ return 1;
+ }
+
+ auto const& expandedPreset = presetPair->second.Expanded;
+ if (!expandedPreset) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Could not evaluate package preset \""
+ << preset << "\": Invalid macro expansion" << std::endl);
+ presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
+ return 1;
+ }
+
+ if (!expandedPreset->ConditionResult) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Cannot use disabled package preset in "
+ << workingDirectory << ": \"" << preset << '"'
+ << std::endl);
+ presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
+ return 1;
+ }
+
+ if (!presetGeneratorsPresent(presetPair->second.Unexpanded)) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Cannot use preset");
+ presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
+ return 1;
+ }
+
+ auto configurePresetPair =
+ presetsGraph.ConfigurePresets.find(expandedPreset->ConfigurePreset);
+ if (configurePresetPair == presetsGraph.ConfigurePresets.end()) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "No such configure preset in "
+ << workingDirectory << ": \""
+ << expandedPreset->ConfigurePreset << '"' << std::endl);
+ presetsGraph.PrintConfigurePresetList();
+ return 1;
+ }
+
+ if (configurePresetPair->second.Unexpanded.Hidden) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Cannot use hidden configure preset in "
+ << workingDirectory << ": \""
+ << expandedPreset->ConfigurePreset << '"' << std::endl);
+ presetsGraph.PrintConfigurePresetList();
+ return 1;
+ }
+
+ auto const& expandedConfigurePreset = configurePresetPair->second.Expanded;
+ if (!expandedConfigurePreset) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Could not evaluate configure preset \""
+ << expandedPreset->ConfigurePreset
+ << "\": Invalid macro expansion" << std::endl);
+ return 1;
+ }
+
+ cmSystemTools::ChangeDirectory(expandedConfigurePreset->BinaryDir);
+
+ auto presetEnvironment = expandedPreset->Environment;
+ for (auto const& var : presetEnvironment) {
+ if (var.second) {
+ cmSystemTools::PutEnv(cmStrCat(var.first, '=', *var.second));
+ }
+ }
+
+ if (!expandedPreset->ConfigFile.empty() && cpackConfigFile.empty()) {
+ cpackConfigFile = expandedPreset->ConfigFile;
+ }
+
+ if (!expandedPreset->Generators.empty() && generator.empty()) {
+ generator = cmJoin(expandedPreset->Generators, ";");
+ }
+
+ if (!expandedPreset->Configurations.empty() && cpackBuildConfig.empty()) {
+ cpackBuildConfig = cmJoin(expandedPreset->Configurations, ";");
+ }
+
+ definitions.insert(expandedPreset->Variables.begin(),
+ expandedPreset->Variables.end());
+
+ if (expandedPreset->DebugOutput == true) {
+ debugLambda("", &cminst, &globalMF);
+ }
+
+ if (expandedPreset->VerboseOutput == true) {
+ verboseLambda("", &cminst, &globalMF);
+ }
+
+ if (!expandedPreset->PackageName.empty() && cpackProjectName.empty()) {
+ cpackProjectName = expandedPreset->PackageName;
+ }
+
+ if (!expandedPreset->PackageVersion.empty() &&
+ cpackProjectVersion.empty()) {
+ cpackProjectVersion = expandedPreset->PackageVersion;
+ }
+
+ if (!expandedPreset->PackageDirectory.empty() &&
+ cpackProjectDirectory.empty()) {
+ cpackProjectDirectory = expandedPreset->PackageDirectory;
+ }
+
+ if (!expandedPreset->VendorName.empty() && cpackProjectVendor.empty()) {
+ cpackProjectVendor = expandedPreset->VendorName;
+ }
+ }
+
cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
"Read CPack config file: " << cpackConfigFile << std::endl);
@@ -238,9 +404,6 @@ int main(int argc, char const* const* argv)
cpackConfigFileSpecified = false;
}
- cmCPackGeneratorFactory generators;
- generators.SetLogger(&log);
-
cmDocumentation doc;
doc.addCPackStandardDocSections();
/* Were we invoked to display doc or to do some work ?
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index 2aba79d..66c30c0 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -893,16 +893,31 @@ int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
// If there was an error running command, report that on the
// dashboard.
if (this->UseCTestLaunch) {
- cmCTestLaunchReporter reporter;
- reporter.RealArgs = args;
- reporter.ComputeFileNames();
- reporter.ExitCode = *retVal;
- reporter.Process = cp;
- // Use temporary BuildLog file to populate this error for CDash.
- ofs.flush();
- reporter.LogOut = this->LogFileNames["Build"];
- reporter.LogOut += ".tmp";
- reporter.WriteXML();
+ // For launchers, do not record this top-level error if other
+ // more granular build errors have already been captured.
+ bool launcherXMLFound = false;
+ cmsys::Directory launchDir;
+ launchDir.Load(this->CTestLaunchDir);
+ unsigned long n = launchDir.GetNumberOfFiles();
+ for (unsigned long i = 0; i < n; ++i) {
+ const char* fname = launchDir.GetFile(i);
+ if (cmHasLiteralSuffix(fname, ".xml")) {
+ launcherXMLFound = true;
+ break;
+ }
+ }
+ if (!launcherXMLFound) {
+ cmCTestLaunchReporter reporter;
+ reporter.RealArgs = args;
+ reporter.ComputeFileNames();
+ reporter.ExitCode = *retVal;
+ reporter.Process = cp;
+ // Use temporary BuildLog file to populate this error for CDash.
+ ofs.flush();
+ reporter.LogOut = this->LogFileNames["Build"];
+ reporter.LogOut += ".tmp";
+ reporter.WriteXML();
+ }
} else {
cmCTestBuildErrorWarning errorwarning;
errorwarning.LineNumber = 0;
diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx
index 7432d08..97b0a89 100644
--- a/Source/CTest/cmCTestCoverageCommand.cxx
+++ b/Source/CTest/cmCTestCoverageCommand.cxx
@@ -4,7 +4,6 @@
#include <set>
-#include <cmext/algorithm>
#include <cmext/string_view>
#include "cmCTest.h"
@@ -18,13 +17,6 @@ void cmCTestCoverageCommand::BindArguments()
this->Bind("LABELS"_s, this->Labels);
}
-void cmCTestCoverageCommand::CheckArguments(
- std::vector<std::string> const& keywords)
-{
- this->LabelsMentioned =
- !this->Labels.empty() || cm::contains(keywords, "LABELS");
-}
-
cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler()
{
this->CTest->SetCTestConfigurationFromCMakeVariable(
@@ -36,9 +28,9 @@ cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler()
handler->Initialize();
// If a LABELS option was given, select only files with the labels.
- if (this->LabelsMentioned) {
+ if (this->Labels) {
handler->SetLabelFilter(
- std::set<std::string>(this->Labels.begin(), this->Labels.end()));
+ std::set<std::string>(this->Labels->begin(), this->Labels->end()));
}
handler->SetQuiet(this->Quiet);
diff --git a/Source/CTest/cmCTestCoverageCommand.h b/Source/CTest/cmCTestCoverageCommand.h
index 9344852..55c68b2 100644
--- a/Source/CTest/cmCTestCoverageCommand.h
+++ b/Source/CTest/cmCTestCoverageCommand.h
@@ -9,7 +9,9 @@
#include <vector>
#include <cm/memory>
+#include <cm/optional>
+#include "cmArgumentParserTypes.h" // IWYU pragma: keep
#include "cmCTestHandlerCommand.h"
#include "cmCommand.h"
@@ -41,9 +43,7 @@ public:
protected:
void BindArguments() override;
- void CheckArguments(std::vector<std::string> const& keywords) override;
cmCTestGenericHandler* InitializeHandler() override;
- bool LabelsMentioned;
- std::vector<std::string> Labels;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Labels;
};
diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx
index 5494d20..be952cd 100644
--- a/Source/CTest/cmCTestHandlerCommand.cxx
+++ b/Source/CTest/cmCTestHandlerCommand.cxx
@@ -7,6 +7,7 @@
#include <cstring>
#include <sstream>
+#include <cm/string_view>
#include <cmext/string_view>
#include "cmCTest.h"
@@ -81,15 +82,13 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
// Process input arguments.
std::vector<std::string> unparsedArguments;
- std::vector<std::string> keywordsMissingValue;
- std::vector<std::string> parsedKeywords;
- this->Parse(args, &unparsedArguments, &keywordsMissingValue,
- &parsedKeywords);
- this->CheckArguments(keywordsMissingValue);
-
- std::sort(parsedKeywords.begin(), parsedKeywords.end());
- auto it = std::adjacent_find(parsedKeywords.begin(), parsedKeywords.end());
- if (it != parsedKeywords.end()) {
+ this->Parse(args, &unparsedArguments);
+ this->CheckArguments();
+
+ std::sort(this->ParsedKeywords.begin(), this->ParsedKeywords.end());
+ auto it = std::adjacent_find(this->ParsedKeywords.begin(),
+ this->ParsedKeywords.end());
+ if (it != this->ParsedKeywords.end()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("Called with more than one value for ", *it));
@@ -233,6 +232,7 @@ void cmCTestHandlerCommand::ProcessAdditionalValues(cmCTestGenericHandler*)
void cmCTestHandlerCommand::BindArguments()
{
+ this->BindParsedKeywords(this->ParsedKeywords);
this->Bind("APPEND"_s, this->Append);
this->Bind("QUIET"_s, this->Quiet);
this->Bind("RETURN_VALUE"_s, this->ReturnValue);
@@ -242,6 +242,6 @@ void cmCTestHandlerCommand::BindArguments()
this->Bind("SUBMIT_INDEX"_s, this->SubmitIndex);
}
-void cmCTestHandlerCommand::CheckArguments(std::vector<std::string> const&)
+void cmCTestHandlerCommand::CheckArguments()
{
}
diff --git a/Source/CTest/cmCTestHandlerCommand.h b/Source/CTest/cmCTestHandlerCommand.h
index 756952d..ed6d9af 100644
--- a/Source/CTest/cmCTestHandlerCommand.h
+++ b/Source/CTest/cmCTestHandlerCommand.h
@@ -7,6 +7,8 @@
#include <string>
#include <vector>
+#include <cm/string_view>
+
#include "cmArgumentParser.h"
#include "cmCTestCommand.h"
@@ -42,8 +44,9 @@ protected:
// Command argument handling.
virtual void BindArguments();
- virtual void CheckArguments(std::vector<std::string> const& keywords);
+ virtual void CheckArguments();
+ std::vector<cm::string_view> ParsedKeywords;
bool Append = false;
bool Quiet = false;
std::string CaptureCMakeError;
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 2a2cb1c..5efe69f 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -8,16 +8,12 @@
#include <cstdint>
#include <cstdio>
#include <cstring>
-#include <functional>
#include <iomanip>
#include <ratio>
#include <sstream>
#include <utility>
#include <cm/memory>
-#include <cm/optional>
-#include <cm/string_view>
-#include <cmext/string_view>
#include "cmsys/RegularExpression.hxx"
@@ -787,149 +783,31 @@ bool cmCTestRunTest::ForkProcess(
this->TestProcess->SetTimeout(timeout);
-#ifndef CMAKE_BOOTSTRAP
cmSystemTools::SaveRestoreEnvironment sre;
-#endif
-
std::ostringstream envMeasurement;
+
+ // We split processing ENVIRONMENT and ENVIRONMENT_MODIFICATION into two
+ // phases to ensure that MYVAR=reset: in the latter phase resets to the
+ // former phase's settings, rather than to the original environment.
if (environment && !environment->empty()) {
- // Environment modification works on the assumption that the environment is
- // actually modified here. If another strategy is used, there will need to
- // be updates below in `apply_diff`.
- cmSystemTools::AppendEnv(*environment);
- for (auto const& var : *environment) {
- envMeasurement << var << std::endl;
- }
+ cmSystemTools::EnvDiff diff;
+ diff.AppendEnv(*environment);
+ diff.ApplyToCurrentEnv(&envMeasurement);
}
if (environment_modification && !environment_modification->empty()) {
- std::map<std::string, cm::optional<std::string>> env_application;
-
-#ifdef _WIN32
- char path_sep = ';';
-#else
- char path_sep = ':';
-#endif
-
- auto apply_diff =
- [&env_application](const std::string& name,
- std::function<void(std::string&)> const& apply) {
- cm::optional<std::string> old_value = env_application[name];
- std::string output;
- if (old_value) {
- output = *old_value;
- } else {
- // This only works because the environment is actually modified above
- // (`AppendEnv`). If CTest ever just creates an environment block
- // directly, that block will need to be queried for the subprocess'
- // value instead.
- const char* curval = cmSystemTools::GetEnv(name);
- if (curval) {
- output = curval;
- }
- }
- apply(output);
- env_application[name] = output;
- };
-
- bool err_occurred = false;
+ cmSystemTools::EnvDiff diff;
+ bool env_ok = true;
for (auto const& envmod : *environment_modification) {
- // Split on `=`
- auto const eq_loc = envmod.find_first_of('=');
- if (eq_loc == std::string::npos) {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error: Missing `=` after the variable name in: "
- << envmod << std::endl);
- err_occurred = true;
- continue;
- }
- auto const name = envmod.substr(0, eq_loc);
-
- // Split value on `:`
- auto const op_value_start = eq_loc + 1;
- auto const colon_loc = envmod.find_first_of(':', op_value_start);
- if (colon_loc == std::string::npos) {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error: Missing `:` after the operation in: " << envmod
- << std::endl);
- err_occurred = true;
- continue;
- }
- auto const op =
- envmod.substr(op_value_start, colon_loc - op_value_start);
-
- auto const value_start = colon_loc + 1;
- auto const value = envmod.substr(value_start);
-
- // Determine what to do with the operation.
- if (op == "reset"_s) {
- auto entry = env_application.find(name);
- if (entry != env_application.end()) {
- env_application.erase(entry);
- }
- } else if (op == "set"_s) {
- env_application[name] = value;
- } else if (op == "unset"_s) {
- env_application[name] = {};
- } else if (op == "string_append"_s) {
- apply_diff(name, [&value](std::string& output) { output += value; });
- } else if (op == "string_prepend"_s) {
- apply_diff(name,
- [&value](std::string& output) { output.insert(0, value); });
- } else if (op == "path_list_append"_s) {
- apply_diff(name, [&value, path_sep](std::string& output) {
- if (!output.empty()) {
- output += path_sep;
- }
- output += value;
- });
- } else if (op == "path_list_prepend"_s) {
- apply_diff(name, [&value, path_sep](std::string& output) {
- if (!output.empty()) {
- output.insert(output.begin(), path_sep);
- }
- output.insert(0, value);
- });
- } else if (op == "cmake_list_append"_s) {
- apply_diff(name, [&value](std::string& output) {
- if (!output.empty()) {
- output += ';';
- }
- output += value;
- });
- } else if (op == "cmake_list_prepend"_s) {
- apply_diff(name, [&value](std::string& output) {
- if (!output.empty()) {
- output.insert(output.begin(), ';');
- }
- output.insert(0, value);
- });
- } else {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error: Unrecognized environment manipulation argument: "
- << op << std::endl);
- err_occurred = true;
- continue;
- }
+ env_ok &= diff.ParseOperation(envmod);
}
- if (err_occurred) {
+ if (!env_ok) {
return false;
}
- for (auto const& env_apply : env_application) {
- if (env_apply.second) {
- auto const env_update =
- cmStrCat(env_apply.first, '=', *env_apply.second);
- cmSystemTools::PutEnv(env_update);
- envMeasurement << env_update << std::endl;
- } else {
- cmSystemTools::UnsetEnv(env_apply.first.c_str());
- // Signify that this variable is being actively unset
- envMeasurement << "#" << env_apply.first << "=" << std::endl;
- }
- }
+ diff.ApplyToCurrentEnv(&envMeasurement);
}
if (this->UseAllocatedResources) {
diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx
index a2dc615..a1933cc 100644
--- a/Source/CTest/cmCTestSubmitCommand.cxx
+++ b/Source/CTest/cmCTestSubmitCommand.cxx
@@ -8,7 +8,6 @@
#include <cm/memory>
#include <cm/vector>
-#include <cmext/algorithm>
#include <cmext/string_view>
#include "cmCTest.h"
@@ -87,7 +86,7 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
// If FILES are given, but not PARTS, only the FILES are submitted
// and *no* PARTS are submitted.
// (This is why we select the empty "noParts" set in the
- // FilesMentioned block below...)
+ // if(this->Files) block below...)
//
// If PARTS are given, only the selected PARTS are submitted.
//
@@ -96,7 +95,7 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
// If given explicit FILES to submit, pass them to the handler.
//
- if (this->FilesMentioned) {
+ if (this->Files) {
// Intentionally select *no* PARTS. (Pass an empty set.) If PARTS
// were also explicitly mentioned, they will be selected below...
// But FILES with no PARTS mentioned should just submit the FILES
@@ -104,14 +103,14 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
//
handler->SelectParts(std::set<cmCTest::Part>());
handler->SelectFiles(
- std::set<std::string>(this->Files.begin(), this->Files.end()));
+ std::set<std::string>(this->Files->begin(), this->Files->end()));
}
// If a PARTS option was given, select only the named parts for submission.
//
- if (this->PartsMentioned) {
+ if (this->Parts) {
auto parts =
- cmMakeRange(this->Parts).transform([this](std::string const& arg) {
+ cmMakeRange(*(this->Parts)).transform([this](std::string const& arg) {
return this->CTest->GetPartFromName(arg);
});
handler->SelectParts(std::set<cmCTest::Part>(parts.begin(), parts.end()));
@@ -172,33 +171,31 @@ void cmCTestSubmitCommand::BindArguments()
this->cmCTestHandlerCommand::BindArguments();
}
-void cmCTestSubmitCommand::CheckArguments(
- std::vector<std::string> const& keywords)
+void cmCTestSubmitCommand::CheckArguments()
{
- this->PartsMentioned =
- !this->Parts.empty() || cm::contains(keywords, "PARTS");
- this->FilesMentioned =
- !this->Files.empty() || cm::contains(keywords, "FILES");
-
- cm::erase_if(this->Parts, [this](std::string const& arg) -> bool {
- cmCTest::Part p = this->CTest->GetPartFromName(arg);
- if (p == cmCTest::PartCount) {
- std::ostringstream e;
- e << "Part name \"" << arg << "\" is invalid.";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
- return true;
- }
- return false;
- });
-
- cm::erase_if(this->Files, [this](std::string const& arg) -> bool {
- if (!cmSystemTools::FileExists(arg)) {
- std::ostringstream e;
- e << "File \"" << arg << "\" does not exist. Cannot submit "
- << "a non-existent file.";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
- return true;
- }
- return false;
- });
+ if (this->Parts) {
+ cm::erase_if(*(this->Parts), [this](std::string const& arg) -> bool {
+ cmCTest::Part p = this->CTest->GetPartFromName(arg);
+ if (p == cmCTest::PartCount) {
+ std::ostringstream e;
+ e << "Part name \"" << arg << "\" is invalid.";
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return true;
+ }
+ return false;
+ });
+ }
+
+ if (this->Files) {
+ cm::erase_if(*(this->Files), [this](std::string const& arg) -> bool {
+ if (!cmSystemTools::FileExists(arg)) {
+ std::ostringstream e;
+ e << "File \"" << arg << "\" does not exist. Cannot submit "
+ << "a non-existent file.";
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return true;
+ }
+ return false;
+ });
+ }
}
diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h
index c5d11df..b67f182 100644
--- a/Source/CTest/cmCTestSubmitCommand.h
+++ b/Source/CTest/cmCTestSubmitCommand.h
@@ -8,6 +8,9 @@
#include <string>
#include <vector>
+#include <cm/optional>
+
+#include "cmArgumentParserTypes.h"
#include "cmCTestHandlerCommand.h"
class cmCommand;
@@ -35,13 +38,11 @@ public:
protected:
void BindArguments() override;
- void CheckArguments(std::vector<std::string> const& keywords) override;
+ void CheckArguments() override;
cmCTestGenericHandler* InitializeHandler() override;
bool CDashUpload = false;
- bool FilesMentioned = false;
bool InternalTest = false;
- bool PartsMentioned = false;
std::string BuildID;
std::string CDashUploadFile;
@@ -50,7 +51,7 @@ protected:
std::string RetryDelay;
std::string SubmitURL;
- std::vector<std::string> Files;
- std::vector<std::string> HttpHeaders;
- std::vector<std::string> Parts;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Files;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> HttpHeaders;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Parts;
};
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index d1fad62..daaf5fd 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -363,7 +363,11 @@ void cmCTestTestHandler::PopulateCustomVectors(cmMakefile* mf)
cmValue dval = mf->GetDefinition("CTEST_CUSTOM_TEST_OUTPUT_TRUNCATION");
if (dval) {
- this->SetTestOutputTruncation(dval);
+ if (!this->SetTestOutputTruncation(dval)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Invalid value for CTEST_CUSTOM_TEST_OUTPUT_TRUNCATION: "
+ << dval << std::endl);
+ }
}
}
diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx
index f86ee0d..2ed671c 100644
--- a/Source/CTest/cmCTestUploadCommand.cxx
+++ b/Source/CTest/cmCTestUploadCommand.cxx
@@ -21,7 +21,7 @@ void cmCTestUploadCommand::BindArguments()
this->Bind("CAPTURE_CMAKE_ERROR"_s, this->CaptureCMakeError);
}
-void cmCTestUploadCommand::CheckArguments(std::vector<std::string> const&)
+void cmCTestUploadCommand::CheckArguments()
{
cm::erase_if(this->Files, [this](std::string const& arg) -> bool {
if (!cmSystemTools::FileExists(arg)) {
diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h
index fe155f6..a9d1dd2 100644
--- a/Source/CTest/cmCTestUploadCommand.h
+++ b/Source/CTest/cmCTestUploadCommand.h
@@ -10,6 +10,7 @@
#include <cm/memory>
+#include "cmArgumentParserTypes.h"
#include "cmCTestHandlerCommand.h"
#include "cmCommand.h"
@@ -42,8 +43,8 @@ public:
protected:
void BindArguments() override;
- void CheckArguments(std::vector<std::string> const&) override;
+ void CheckArguments() override;
cmCTestGenericHandler* InitializeHandler() override;
- std::vector<std::string> Files;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Files;
};
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx
index 73e3f3c..6e6f0d6 100644
--- a/Source/CursesDialog/cmCursesLongMessageForm.cxx
+++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx
@@ -43,7 +43,8 @@ void cmCursesLongMessageForm::UpdateContent(std::string const& output,
if (!output.empty() && this->Messages.size() < MAX_CONTENT_SIZE) {
this->Messages.push_back('\n');
this->Messages.append(output);
- form_driver(this->Form, REQ_NEW_LINE);
+ form_driver(this->Form, REQ_NEXT_LINE);
+ form_driver(this->Form, REQ_BEG_LINE);
this->DrawMessage(output.c_str());
}
@@ -152,7 +153,8 @@ void cmCursesLongMessageForm::DrawMessage(const char* msg) const
int i = 0;
while (msg[i] != '\0' && i < MAX_CONTENT_SIZE) {
if (msg[i] == '\n' && msg[i + 1] != '\0') {
- form_driver(this->Form, REQ_NEW_LINE);
+ form_driver(this->Form, REQ_NEXT_LINE);
+ form_driver(this->Form, REQ_BEG_LINE);
} else {
form_driver(this->Form, msg[i]);
}
diff --git a/Source/CursesDialog/form/CMakeLists.txt b/Source/CursesDialog/form/CMakeLists.txt
index 68d28c8..63214e3 100644
--- a/Source/CursesDialog/form/CMakeLists.txt
+++ b/Source/CursesDialog/form/CMakeLists.txt
@@ -11,7 +11,7 @@ elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
endif()
-configure_file(cmFormConfigure.h.in "${CMAKE_CURRENT_BINARY_DIR}/cmFormConfigure.h")
+configure_file(cmFormConfigure.h.in cmFormConfigure.h)
add_library(cmForm
fld_arg.c
diff --git a/Source/LexerParser/cmFortranLexer.cxx b/Source/LexerParser/cmFortranLexer.cxx
index c3d0000..5703de1 100644
--- a/Source/LexerParser/cmFortranLexer.cxx
+++ b/Source/LexerParser/cmFortranLexer.cxx
@@ -557,31 +557,32 @@ struct yy_trans_info
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
-static const flex_int16_t yy_accept[210] =
+static const flex_int16_t yy_accept[216] =
{ 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55, 49, 51, 50, 53, 1, 49, 33, 2, 47,
48, 35, 37, 50, 39, 49, 46, 46, 46, 46,
- 46, 46, 49, 46, 51, 49, 50, 49, 46, 9,
- 8, 9, 4, 3, 49, 0, 10, 0, 0, 0,
- 0, 0, 33, 33, 34, 36, 39, 49, 46, 46,
- 46, 46, 46, 46, 0, 52, 46, 0, 0, 0,
- 12, 0, 0, 0, 0, 0, 0, 49, 0, 11,
- 46, 0, 0, 5, 0, 0, 0, 0, 29, 0,
- 33, 33, 33, 33, 0, 0, 40, 46, 46, 46,
-
- 46, 45, 12, 12, 0, 0, 0, 23, 0, 0,
- 0, 0, 0, 0, 6, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 46, 46, 46, 46, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 30, 31, 0, 0, 0, 0, 0, 46, 46,
- 46, 46, 0, 24, 25, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 20, 32, 27, 0, 0, 0,
- 46, 46, 43, 46, 0, 26, 21, 0, 0, 0,
- 19, 0, 0, 18, 28, 0, 0, 41, 46, 46,
- 17, 22, 0, 7, 38, 7, 15, 0, 46, 46,
-
- 14, 16, 42, 44, 0, 0, 0, 13, 0
+ 46, 46, 49, 46, 51, 49, 50, 51, 49, 46,
+ 9, 8, 9, 9, 4, 3, 49, 0, 10, 0,
+ 0, 0, 0, 0, 33, 33, 34, 36, 39, 49,
+ 46, 46, 46, 46, 46, 46, 0, 52, 0, 46,
+ 0, 0, 0, 12, 0, 0, 0, 0, 0, 0,
+ 0, 49, 0, 11, 46, 0, 0, 0, 5, 0,
+ 0, 0, 0, 0, 29, 0, 33, 33, 33, 33,
+
+ 0, 0, 40, 46, 46, 46, 46, 45, 12, 12,
+ 0, 0, 0, 23, 0, 0, 0, 0, 0, 0,
+ 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 46, 46, 46, 46, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 30, 31, 0,
+ 0, 0, 0, 0, 46, 46, 46, 46, 0, 24,
+ 25, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 20, 32, 27, 0, 0, 0, 46, 46, 43, 46,
+ 0, 26, 21, 0, 0, 0, 19, 0, 0, 18,
+ 28, 0, 0, 41, 46, 46, 17, 22, 0, 7,
+
+ 38, 7, 15, 0, 46, 46, 14, 16, 42, 44,
+ 0, 0, 0, 13, 0
} ;
static const YY_CHAR yy_ec[256] =
@@ -618,189 +619,197 @@ static const YY_CHAR yy_ec[256] =
static const YY_CHAR yy_meta[50] =
{ 0,
- 1, 2, 2, 3, 4, 3, 3, 1, 1, 3,
- 3, 3, 3, 1, 3, 5, 3, 3, 1, 3,
+ 1, 2, 2, 2, 3, 4, 4, 1, 1, 4,
+ 4, 4, 4, 1, 4, 5, 4, 4, 1, 4,
6, 1, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 1, 5,
7, 7, 7, 7, 7, 7, 7, 7, 7
} ;
-static const flex_int16_t yy_base[219] =
+static const flex_int16_t yy_base[225] =
{ 0,
- 0, 48, 0, 49, 464, 56, 52, 57, 62, 68,
- 466, 0, 468, 468, 462, 468, 74, 81, 468, 468,
- 468, 468, 447, 468, 442, 440, 0, 19, 41, 427,
- 47, 41, 90, 119, 97, 158, 455, 207, 247, 468,
- 454, 101, 468, 468, 0, 455, 468, 105, 430, 423,
- 62, 67, 119, 151, 468, 468, 468, 121, 0, 90,
- 93, 110, 431, 112, 142, 468, 0, 160, 295, 0,
- 162, 411, 123, 102, 408, 405, 446, 344, 447, 468,
- 0, 444, 170, 174, 420, 421, 132, 404, 95, 404,
- 180, 186, 192, 228, 297, 397, 0, 168, 144, 52,
-
- 411, 0, 204, 217, 397, 179, 390, 170, 389, 378,
- 364, 390, 389, 230, 468, 363, 355, 337, 337, 334,
- 335, 335, 330, 334, 187, 339, 267, 339, 327, 327,
- 327, 324, 325, 325, 318, 319, 318, 354, 352, 323,
- 327, 468, 468, 310, 307, 305, 297, 297, 275, 275,
- 277, 279, 287, 468, 468, 286, 283, 273, 196, 307,
- 200, 238, 234, 210, 468, 468, 468, 174, 171, 162,
- 279, 182, 0, 269, 150, 468, 468, 137, 109, 323,
- 468, 239, 0, 468, 468, 72, 71, 0, 283, 283,
- 468, 468, 51, 468, 468, 468, 468, 37, 283, 288,
-
- 330, 468, 0, 0, 331, 0, 52, 468, 468, 384,
- 391, 397, 400, 407, 414, 421, 428, 435
+ 0, 48, 0, 49, 55, 58, 64, 66, 75, 83,
+ 491, 0, 492, 492, 487, 492, 86, 92, 492, 492,
+ 492, 492, 472, 492, 467, 465, 0, 56, 59, 452,
+ 66, 16, 105, 131, 109, 170, 480, 481, 219, 259,
+ 492, 478, 479, 116, 492, 492, 0, 478, 492, 111,
+ 453, 446, 34, 78, 155, 174, 492, 492, 492, 121,
+ 0, 29, 105, 101, 454, 101, 131, 492, 474, 0,
+ 180, 307, 0, 146, 433, 117, 94, 430, 427, 468,
+ 467, 356, 468, 492, 0, 465, 464, 187, 191, 465,
+ 439, 440, 149, 423, 126, 423, 200, 240, 311, 322,
+
+ 206, 416, 0, 152, 180, 176, 430, 0, 216, 224,
+ 417, 186, 418, 127, 418, 411, 415, 451, 450, 247,
+ 492, 423, 416, 398, 393, 373, 364, 364, 359, 353,
+ 198, 358, 178, 358, 346, 346, 346, 343, 344, 344,
+ 338, 340, 339, 376, 374, 343, 346, 492, 492, 329,
+ 325, 324, 313, 315, 211, 211, 291, 293, 313, 492,
+ 492, 314, 304, 304, 261, 328, 212, 249, 243, 203,
+ 492, 492, 492, 173, 158, 150, 293, 172, 0, 273,
+ 144, 492, 492, 137, 125, 335, 492, 339, 0, 492,
+ 492, 112, 63, 0, 304, 300, 492, 492, 58, 492,
+
+ 492, 492, 492, 30, 311, 312, 361, 492, 0, 0,
+ 366, 0, 44, 492, 492, 396, 403, 409, 412, 419,
+ 426, 433, 440, 447
} ;
-static const flex_int16_t yy_def[219] =
+static const flex_int16_t yy_def[225] =
{ 0,
- 209, 1, 1, 1, 1, 1, 210, 210, 210, 210,
- 209, 211, 209, 209, 212, 209, 211, 209, 209, 209,
- 209, 209, 209, 209, 209, 211, 213, 213, 213, 213,
- 213, 213, 211, 213, 209, 211, 209, 214, 209, 209,
- 209, 209, 209, 209, 211, 212, 209, 209, 209, 209,
- 209, 209, 209, 215, 209, 209, 209, 211, 213, 213,
- 213, 213, 213, 213, 209, 209, 34, 209, 209, 69,
- 211, 209, 209, 209, 209, 209, 209, 214, 214, 209,
- 39, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 215, 215, 215, 215, 209, 209, 213, 213, 213, 213,
-
- 213, 213, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 213, 213, 213, 213, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 213, 213,
- 213, 213, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 213, 213, 213, 213, 209, 209, 209, 209, 209, 209,
- 209, 216, 217, 209, 209, 209, 209, 213, 213, 213,
- 209, 209, 209, 209, 209, 209, 209, 209, 213, 213,
-
- 209, 209, 213, 213, 209, 218, 218, 209, 0, 209,
- 209, 209, 209, 209, 209, 209, 209, 209
+ 215, 1, 1, 1, 1, 1, 216, 216, 216, 216,
+ 215, 217, 215, 215, 218, 215, 217, 215, 215, 215,
+ 215, 215, 215, 215, 215, 217, 219, 219, 219, 219,
+ 219, 219, 217, 219, 215, 217, 215, 215, 220, 215,
+ 215, 215, 215, 215, 215, 215, 217, 218, 215, 215,
+ 215, 215, 215, 215, 215, 221, 215, 215, 215, 217,
+ 219, 219, 219, 219, 219, 219, 215, 215, 215, 34,
+ 215, 215, 72, 217, 215, 215, 215, 215, 215, 215,
+ 215, 220, 220, 215, 40, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 221, 221, 221, 221,
+
+ 215, 215, 219, 219, 219, 219, 219, 219, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 219, 219, 219, 219, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 219, 219, 219, 219, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 219, 219, 219, 219,
+ 215, 215, 215, 215, 215, 215, 215, 222, 223, 215,
+ 215, 215, 215, 219, 219, 219, 215, 215, 215, 215,
+
+ 215, 215, 215, 215, 219, 219, 215, 215, 219, 219,
+ 215, 224, 224, 215, 0, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215
} ;
-static const flex_int16_t yy_nxt[518] =
+static const flex_int16_t yy_nxt[542] =
{ 0,
12, 13, 14, 13, 13, 15, 16, 12, 17, 18,
19, 20, 21, 12, 22, 12, 23, 24, 12, 25,
12, 26, 27, 27, 27, 27, 28, 27, 27, 29,
27, 30, 27, 27, 27, 31, 27, 32, 33, 34,
27, 27, 28, 27, 29, 27, 27, 31, 32, 35,
- 35, 60, 35, 35, 41, 36, 36, 35, 37, 41,
- 35, 42, 43, 36, 41, 60, 42, 43, 44, 38,
- 41, 42, 208, 61, 44, 48, 64, 42, 48, 202,
- 39, 39, 53, 53, 63, 53, 54, 61, 64, 127,
- 55, 65, 66, 201, 65, 63, 39, 39, 68, 49,
-
- 127, 68, 83, 84, 69, 83, 48, 87, 88, 48,
- 89, 50, 198, 90, 197, 97, 51, 98, 52, 45,
- 53, 53, 95, 53, 54, 95, 45, 45, 55, 99,
- 49, 97, 45, 98, 67, 100, 121, 45, 102, 45,
- 45, 122, 50, 65, 66, 108, 65, 51, 109, 52,
- 193, 100, 92, 53, 102, 92, 93, 45, 67, 70,
- 94, 68, 70, 104, 68, 96, 104, 69, 106, 107,
- 126, 83, 84, 71, 83, 114, 118, 71, 114, 119,
- 192, 92, 53, 115, 92, 93, 126, 92, 53, 94,
- 92, 93, 191, 92, 53, 94, 92, 93, 125, 72,
-
- 73, 94, 74, 75, 189, 104, 76, 78, 104, 80,
- 187, 133, 186, 125, 78, 78, 134, 185, 104, 103,
- 78, 104, 78, 130, 149, 78, 131, 78, 78, 92,
- 53, 114, 92, 93, 114, 149, 184, 94, 183, 115,
- 195, 195, 182, 181, 179, 78, 78, 79, 79, 80,
- 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
- 79, 79, 81, 79, 79, 79, 79, 79, 79, 81,
- 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
- 81, 81, 81, 81, 81, 79, 81, 81, 81, 81,
- 81, 81, 81, 81, 81, 81, 70, 151, 95, 70,
-
- 171, 95, 172, 173, 174, 188, 190, 199, 180, 203,
- 103, 180, 151, 200, 204, 178, 171, 190, 172, 173,
- 174, 188, 103, 199, 180, 203, 177, 180, 200, 176,
- 204, 205, 205, 175, 205, 205, 72, 73, 103, 74,
- 75, 96, 170, 76, 78, 169, 80, 168, 206, 206,
- 167, 78, 78, 166, 165, 164, 163, 78, 162, 78,
- 161, 160, 78, 159, 78, 78, 158, 157, 156, 155,
- 154, 153, 152, 150, 148, 147, 146, 145, 144, 143,
- 142, 141, 78, 78, 40, 40, 40, 40, 40, 40,
- 40, 45, 140, 139, 138, 45, 45, 46, 46, 46,
-
- 46, 46, 46, 46, 59, 137, 59, 79, 79, 79,
- 79, 79, 79, 79, 91, 91, 91, 91, 91, 91,
- 91, 194, 194, 194, 136, 194, 194, 194, 196, 135,
- 196, 132, 196, 196, 196, 207, 207, 207, 207, 207,
- 129, 207, 128, 124, 123, 120, 117, 116, 113, 80,
- 112, 111, 110, 105, 101, 86, 85, 47, 82, 77,
- 62, 58, 57, 56, 47, 209, 37, 11, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
-
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209
+ 35, 66, 35, 35, 103, 36, 36, 37, 38, 35,
+ 37, 38, 35, 66, 214, 36, 42, 43, 42, 43,
+ 103, 39, 208, 44, 45, 44, 45, 42, 43, 93,
+ 94, 46, 40, 40, 44, 42, 43, 50, 62, 46,
+ 50, 63, 44, 55, 55, 55, 55, 56, 40, 40,
+
+ 207, 57, 62, 65, 204, 63, 67, 68, 69, 67,
+ 71, 51, 50, 71, 65, 50, 72, 88, 89, 90,
+ 88, 95, 101, 52, 96, 101, 106, 108, 53, 104,
+ 54, 47, 67, 68, 69, 67, 51, 114, 47, 47,
+ 115, 105, 106, 108, 47, 104, 70, 110, 52, 47,
+ 110, 47, 47, 53, 203, 54, 55, 55, 55, 55,
+ 56, 74, 112, 113, 57, 102, 199, 127, 139, 47,
+ 70, 73, 128, 140, 73, 98, 55, 98, 98, 99,
+ 198, 71, 131, 100, 71, 74, 197, 72, 88, 89,
+ 90, 88, 120, 124, 195, 120, 125, 131, 193, 192,
+
+ 121, 98, 55, 98, 98, 99, 132, 101, 157, 100,
+ 101, 75, 76, 133, 77, 78, 191, 110, 79, 82,
+ 110, 84, 132, 157, 133, 110, 82, 82, 110, 190,
+ 136, 109, 82, 137, 82, 155, 177, 82, 178, 82,
+ 82, 98, 55, 98, 98, 99, 155, 189, 120, 100,
+ 102, 120, 177, 188, 178, 187, 121, 82, 82, 83,
+ 83, 84, 83, 83, 83, 83, 83, 83, 83, 83,
+ 83, 83, 83, 83, 85, 83, 83, 83, 83, 83,
+ 83, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+ 85, 85, 85, 85, 85, 85, 85, 83, 85, 85,
+
+ 85, 85, 85, 85, 85, 85, 85, 85, 73, 185,
+ 196, 73, 98, 55, 98, 98, 99, 179, 180, 194,
+ 100, 196, 109, 98, 55, 98, 98, 99, 205, 186,
+ 206, 100, 186, 179, 180, 194, 186, 209, 210, 186,
+ 201, 201, 201, 109, 205, 206, 184, 183, 75, 76,
+ 109, 77, 78, 209, 210, 79, 82, 182, 84, 181,
+ 176, 175, 211, 82, 82, 211, 174, 211, 173, 82,
+ 211, 82, 172, 171, 82, 170, 82, 82, 169, 212,
+ 168, 167, 166, 165, 212, 164, 163, 162, 161, 160,
+ 159, 158, 156, 154, 82, 82, 41, 41, 41, 41,
+
+ 41, 41, 41, 47, 153, 152, 151, 47, 47, 48,
+ 48, 48, 48, 48, 48, 48, 61, 150, 61, 83,
+ 83, 83, 83, 83, 83, 83, 97, 97, 97, 97,
+ 97, 97, 97, 200, 200, 149, 200, 200, 200, 200,
+ 202, 148, 147, 202, 202, 202, 202, 213, 213, 213,
+ 213, 213, 146, 213, 145, 144, 143, 142, 141, 138,
+ 135, 134, 130, 129, 126, 123, 122, 89, 86, 119,
+ 84, 80, 118, 117, 116, 111, 68, 107, 92, 91,
+ 49, 87, 86, 81, 80, 64, 60, 59, 58, 49,
+ 215, 11, 215, 215, 215, 215, 215, 215, 215, 215,
+
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215
} ;
-static const flex_int16_t yy_chk[518] =
+static const flex_int16_t yy_chk[542] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
- 4, 28, 2, 4, 7, 2, 4, 6, 6, 8,
- 6, 7, 7, 6, 9, 28, 8, 8, 9, 6,
- 10, 9, 207, 29, 10, 17, 32, 10, 17, 198,
- 6, 6, 18, 18, 31, 18, 18, 29, 32, 100,
- 18, 33, 33, 193, 33, 31, 6, 6, 35, 17,
-
- 100, 35, 42, 42, 35, 42, 48, 51, 51, 48,
- 52, 17, 187, 52, 186, 60, 17, 61, 17, 34,
- 53, 53, 58, 53, 53, 58, 34, 34, 53, 61,
- 48, 60, 34, 61, 34, 62, 89, 34, 64, 34,
- 34, 89, 48, 65, 65, 74, 65, 48, 74, 48,
- 179, 62, 54, 54, 64, 54, 54, 34, 34, 36,
- 54, 68, 36, 71, 68, 58, 71, 68, 73, 73,
- 99, 83, 83, 36, 83, 84, 87, 71, 84, 87,
- 178, 91, 91, 84, 91, 91, 99, 92, 92, 91,
- 92, 92, 175, 93, 93, 92, 93, 93, 98, 36,
-
- 36, 93, 36, 36, 172, 103, 36, 38, 103, 38,
- 170, 108, 169, 98, 38, 38, 108, 168, 104, 103,
- 38, 104, 38, 106, 125, 38, 106, 38, 38, 94,
- 94, 114, 94, 94, 114, 125, 164, 94, 163, 114,
- 182, 182, 162, 161, 159, 38, 38, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 69, 127, 95, 69,
-
- 149, 95, 150, 151, 152, 171, 174, 189, 160, 199,
- 69, 160, 127, 190, 200, 158, 149, 174, 150, 151,
- 152, 171, 160, 189, 180, 199, 157, 180, 190, 156,
- 200, 201, 205, 153, 201, 205, 69, 69, 180, 69,
- 69, 95, 148, 69, 78, 147, 78, 146, 201, 205,
- 145, 78, 78, 144, 141, 140, 139, 78, 138, 78,
- 137, 136, 78, 135, 78, 78, 134, 133, 132, 131,
- 130, 129, 128, 126, 124, 123, 122, 121, 120, 119,
- 118, 117, 78, 78, 210, 210, 210, 210, 210, 210,
- 210, 211, 116, 113, 112, 211, 211, 212, 212, 212,
-
- 212, 212, 212, 212, 213, 111, 213, 214, 214, 214,
- 214, 214, 214, 214, 215, 215, 215, 215, 215, 215,
- 215, 216, 216, 216, 110, 216, 216, 216, 217, 109,
- 217, 107, 217, 217, 217, 218, 218, 218, 218, 218,
- 105, 218, 101, 96, 90, 88, 86, 85, 82, 79,
- 77, 76, 75, 72, 63, 50, 49, 46, 41, 37,
- 30, 26, 25, 23, 15, 11, 5, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
-
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209
+ 4, 32, 2, 4, 62, 2, 4, 5, 5, 6,
+ 6, 6, 6, 32, 213, 6, 7, 7, 8, 8,
+ 62, 6, 204, 7, 7, 8, 8, 9, 9, 53,
+ 53, 9, 6, 6, 9, 10, 10, 17, 28, 10,
+ 17, 29, 10, 18, 18, 18, 18, 18, 6, 6,
+
+ 199, 18, 28, 31, 193, 29, 33, 33, 33, 33,
+ 35, 17, 50, 35, 31, 50, 35, 44, 44, 44,
+ 44, 54, 60, 17, 54, 60, 64, 66, 17, 63,
+ 17, 34, 67, 67, 67, 67, 50, 77, 34, 34,
+ 77, 63, 64, 66, 34, 63, 34, 74, 50, 34,
+ 74, 34, 34, 50, 192, 50, 55, 55, 55, 55,
+ 55, 74, 76, 76, 55, 60, 185, 95, 114, 34,
+ 34, 36, 95, 114, 36, 56, 56, 56, 56, 56,
+ 184, 71, 104, 56, 71, 36, 181, 71, 88, 88,
+ 88, 88, 89, 93, 178, 89, 93, 104, 176, 175,
+
+ 89, 97, 97, 97, 97, 97, 105, 101, 133, 97,
+ 101, 36, 36, 106, 36, 36, 174, 109, 36, 39,
+ 109, 39, 105, 133, 106, 110, 39, 39, 110, 170,
+ 112, 109, 39, 112, 39, 131, 155, 39, 156, 39,
+ 39, 98, 98, 98, 98, 98, 131, 169, 120, 98,
+ 101, 120, 155, 168, 156, 167, 120, 39, 39, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+
+ 40, 40, 40, 40, 40, 40, 40, 40, 72, 165,
+ 180, 72, 99, 99, 99, 99, 99, 157, 158, 177,
+ 99, 180, 72, 100, 100, 100, 100, 100, 195, 166,
+ 196, 100, 166, 157, 158, 177, 186, 205, 206, 186,
+ 188, 188, 188, 166, 195, 196, 164, 163, 72, 72,
+ 186, 72, 72, 205, 206, 72, 82, 162, 82, 159,
+ 154, 153, 207, 82, 82, 207, 152, 211, 151, 82,
+ 211, 82, 150, 147, 82, 146, 82, 82, 145, 207,
+ 144, 143, 142, 141, 211, 140, 139, 138, 137, 136,
+ 135, 134, 132, 130, 82, 82, 216, 216, 216, 216,
+
+ 216, 216, 216, 217, 129, 128, 127, 217, 217, 218,
+ 218, 218, 218, 218, 218, 218, 219, 126, 219, 220,
+ 220, 220, 220, 220, 220, 220, 221, 221, 221, 221,
+ 221, 221, 221, 222, 222, 125, 222, 222, 222, 222,
+ 223, 124, 123, 223, 223, 223, 223, 224, 224, 224,
+ 224, 224, 122, 224, 119, 118, 117, 116, 115, 113,
+ 111, 107, 102, 96, 94, 92, 91, 90, 87, 86,
+ 83, 81, 80, 79, 78, 75, 69, 65, 52, 51,
+ 48, 43, 42, 38, 37, 30, 26, 25, 23, 15,
+ 11, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+ 215
} ;
/* The intent behind this definition is that it'll catch
@@ -1139,13 +1148,13 @@ yy_match:
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 210 )
+ if ( yy_current_state >= 216 )
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
++yy_cp;
}
- while ( yy_base[yy_current_state] != 468 );
+ while ( yy_base[yy_current_state] != 492 );
yy_find_action:
yy_act = yy_accept[yy_current_state];
@@ -1733,7 +1742,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 210 )
+ if ( yy_current_state >= 216 )
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
@@ -1762,11 +1771,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 210 )
+ if ( yy_current_state >= 216 )
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
- yy_is_jam = (yy_current_state == 209);
+ yy_is_jam = (yy_current_state == 215);
(void)yyg;
return yy_is_jam ? 0 : yy_current_state;
diff --git a/Source/LexerParser/cmFortranLexer.in.l b/Source/LexerParser/cmFortranLexer.in.l
index 05769a1..fac3181 100644
--- a/Source/LexerParser/cmFortranLexer.in.l
+++ b/Source/LexerParser/cmFortranLexer.in.l
@@ -75,10 +75,10 @@ Modify cmFortranLexer.cxx:
return STRING;
}
-<str_dq,str_sq>&[ \t]*\n |
-<str_dq,str_sq>&[ \t]*\n[ \t]*& /* Ignore (continued strings, free fmt) */
+<str_dq,str_sq>&[ \t]*\r?\n |
+<str_dq,str_sq>&[ \t]*\r?\n[ \t]*& /* Ignore (continued strings, free fmt) */
-<fixed_fmt,str_dq,str_sq>\n[ ]{5}[^ \t\n] {
+<fixed_fmt,str_dq,str_sq>\r?\n[ ]{5}[^ \t\r\n] {
if (cmFortranParser_GetOldStartcond(yyextra) == fixed_fmt)
; /* Ignore (cont. strings, fixed fmt) */
else
@@ -132,15 +132,15 @@ $[ \t]*else { return F90PPR_ELSE; }
$[ \t]*endif { return F90PPR_ENDIF; }
/* Line continuations, possible involving comments. */
-&([ \t\n]*|!.*)*
-&([ \t\n]*|!.*)*&
+&([ \t\r\n]*|!.*)*
+&([ \t\r\n]*|!.*)*&
, { return COMMA; }
:: { return DCOLON; }
: { return COLON; }
-<fixed_fmt>\n[ ]{5}[^ ] { return GARBAGE; }
+<fixed_fmt>\r?\n[ ]{5}[^ ] { return GARBAGE; }
=|=> { return ASSIGNMENT_OP; }
@@ -159,13 +159,13 @@ $[ \t]*endif { return F90PPR_ENDIF; }
\( { return LPAREN; }
\) { return RPAREN; }
-[^ \t\n\r:;,!'"a-zA-Z=&()]+ { return GARBAGE; }
+[^ \t\r\n:;,!'"a-zA-Z=&()]+ { return GARBAGE; }
;|\n { return EOSTMT; }
[ \t\r,] /* Ignore */
-\\[ \t]*\n /* Ignore line-endings preceded by \ */
+\\[ \t]*\r?\n /* Ignore line-endings preceded by \ */
. { return *yytext; }
diff --git a/Source/LexerParser/cmFortranParser.cxx b/Source/LexerParser/cmFortranParser.cxx
index b177296..5e5cc0b 100644
--- a/Source/LexerParser/cmFortranParser.cxx
+++ b/Source/LexerParser/cmFortranParser.cxx
@@ -548,7 +548,7 @@ union yyalloc
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 2
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 594
+#define YYLAST 432
/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 41
@@ -557,7 +557,7 @@ union yyalloc
/* YYNRULES -- Number of rules. */
#define YYNRULES 64
/* YYNSTATES -- Number of states. */
-#define YYNSTATES 127
+#define YYNSTATES 121
/* YYMAXUTOK -- Last valid token kind. */
#define YYMAXUTOK 295
@@ -608,15 +608,15 @@ static const yytype_int8 yytranslate[] =
#if YYDEBUG
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
-static const yytype_int16 yyrline[] =
+static const yytype_uint8 yyrline[] =
{
- 0, 106, 106, 106, 109, 113, 118, 127, 133, 140,
- 145, 149, 154, 166, 171, 176, 181, 186, 191, 196,
- 201, 206, 210, 214, 218, 222, 223, 228, 228, 228,
- 229, 229, 230, 230, 231, 231, 232, 232, 233, 233,
- 234, 234, 235, 235, 236, 236, 237, 237, 240, 241,
- 242, 243, 244, 245, 246, 247, 248, 249, 250, 251,
- 252, 253, 254, 255, 256
+ 0, 106, 106, 106, 109, 113, 118, 123, 129, 136,
+ 141, 145, 150, 162, 167, 172, 177, 182, 187, 192,
+ 197, 202, 206, 210, 214, 218, 219, 224, 224, 224,
+ 225, 225, 226, 226, 227, 227, 228, 228, 229, 229,
+ 230, 230, 231, 231, 232, 232, 233, 233, 236, 237,
+ 238, 239, 240, 241, 242, 243, 244, 245, 246, 247,
+ 248, 249, 250, 251, 252
};
#endif
@@ -666,19 +666,19 @@ yysymbol_name (yysymbol_kind_t yysymbol)
STATE-NUM. */
static const yytype_int16 yypact[] =
{
- -39, 21, -39, 1, -39, -20, -39, -39, -39, -39,
+ -39, 21, -39, 5, -39, -23, -39, -39, -39, -39,
-39, -39, -39, -39, -39, -39, -39, -39, -39, -39,
- -39, -39, -39, -39, -39, -39, -24, -18, 20, -8,
- -3, 40, -39, 15, 16, 17, 19, 34, -39, -39,
- -39, -39, -39, -39, 59, -39, -39, -39, -39, -39,
- 36, 37, 38, -39, -39, -39, -39, -39, -39, 77,
- 115, 130, 168, 183, -39, -39, -39, -39, -39, -39,
+ -39, -39, -39, -39, -39, -39, -25, -19, 20, -8,
+ -15, -22, -39, -6, 14, 15, 16, 17, -39, -39,
+ -39, -39, -39, -39, 59, 49, 51, -39, 63, 64,
+ 35, 36, 37, -39, -39, -39, -39, -39, -39, 74,
+ 112, 127, 165, 180, -39, -39, -39, -39, -39, -39,
-39, -39, -39, -39, -39, -39, -39, -39, -39, -39,
- -39, -39, -39, 221, 236, 274, 289, -21, 26, -39,
- 327, 342, 380, 395, 433, 448, -39, -39, -39, -39,
- -39, -39, -39, -39, -39, 39, 41, 42, 486, -39,
- -39, -39, -39, -39, -39, 18, -39, -39, -39, 43,
- 501, 539, -39, -39, -39, 554, -39
+ -39, -39, -39, -39, -39, -39, -39, -20, 43, -39,
+ 218, 233, 271, 286, 324, 339, -39, -39, -39, -39,
+ -39, 39, 40, 41, 377, -39, -39, -39, -39, -39,
+ -39, 46, 78, -39, -39, 50, -39, 392, 79, -39,
+ -39
};
/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -690,15 +690,15 @@ static const yytype_int8 yydefact[] =
30, 33, 32, 34, 36, 38, 42, 40, 44, 35,
37, 39, 43, 41, 45, 46, 0, 0, 0, 0,
0, 0, 3, 0, 0, 0, 0, 0, 46, 46,
- 46, 46, 26, 46, 0, 46, 46, 4, 46, 46,
+ 46, 46, 26, 46, 0, 0, 0, 4, 0, 0,
0, 0, 0, 46, 46, 46, 46, 46, 46, 0,
0, 0, 0, 0, 15, 57, 56, 64, 62, 58,
59, 60, 61, 63, 55, 48, 49, 50, 51, 52,
- 53, 54, 47, 0, 0, 0, 0, 0, 0, 46,
+ 53, 54, 47, 10, 13, 9, 6, 0, 0, 46,
0, 0, 0, 0, 0, 0, 21, 22, 23, 24,
- 14, 10, 13, 9, 6, 0, 0, 0, 0, 5,
- 16, 17, 18, 19, 20, 0, 46, 46, 11, 0,
- 0, 0, 46, 7, 12, 0, 8
+ 14, 0, 0, 0, 0, 5, 16, 17, 18, 19,
+ 20, 0, 0, 46, 11, 0, 7, 0, 0, 12,
+ 8
};
/* YYPGOTO[NTERM-NUM]. */
@@ -720,81 +720,70 @@ static const yytype_int8 yydefgoto[] =
number is the opposite. If YYTABLE_NINF, syntax error. */
static const yytype_int8 yytable[] =
{
- 59, 60, 61, 62, 42, 63, 105, 83, 84, 106,
- 85, 86, 43, 45, 46, 90, 91, 92, 93, 94,
- 95, 2, 3, 47, 4, 49, 50, 5, 6, 7,
+ 59, 60, 61, 62, 51, 63, 52, 101, 42, 43,
+ 102, 53, 45, 46, 50, 90, 91, 92, 93, 94,
+ 95, 2, 3, 47, 4, 49, 54, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 54, 119, 55,
- 56, 108, 57, 48, 107, 25, 26, 27, 28, 29,
- 30, 31, 64, 65, 66, 67, 51, 58, 52, 87,
- 88, 89, 115, 53, 116, 117, 122, 0, 120, 121,
- 96, 65, 66, 67, 125, 68, 69, 70, 71, 72,
+ 18, 19, 20, 21, 22, 23, 24, 55, 56, 57,
+ 58, 104, 83, 48, 84, 25, 26, 27, 28, 29,
+ 30, 31, 64, 65, 66, 67, 85, 86, 87, 88,
+ 89, 103, 111, 112, 113, 117, 115, 96, 65, 66,
+ 67, 116, 120, 118, 0, 68, 69, 70, 71, 72,
73, 74, 75, 0, 76, 77, 78, 79, 80, 81,
- 0, 0, 0, 68, 69, 70, 71, 72, 73, 74,
- 75, 0, 76, 77, 78, 79, 80, 81, 97, 65,
+ 68, 69, 70, 71, 72, 73, 74, 75, 0, 76,
+ 77, 78, 79, 80, 81, 97, 65, 66, 67, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 98, 65, 66, 67, 0, 0, 0, 0, 68, 69,
+ 70, 71, 72, 73, 74, 75, 0, 76, 77, 78,
+ 79, 80, 81, 68, 69, 70, 71, 72, 73, 74,
+ 75, 0, 76, 77, 78, 79, 80, 81, 99, 65,
66, 67, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 98, 65, 66, 67, 0, 0, 0,
+ 0, 0, 0, 100, 65, 66, 67, 0, 0, 0,
0, 68, 69, 70, 71, 72, 73, 74, 75, 0,
76, 77, 78, 79, 80, 81, 68, 69, 70, 71,
72, 73, 74, 75, 0, 76, 77, 78, 79, 80,
- 81, 99, 65, 66, 67, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 100, 65, 66, 67,
+ 81, 105, 65, 66, 67, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 106, 65, 66, 67,
0, 0, 0, 0, 68, 69, 70, 71, 72, 73,
74, 75, 0, 76, 77, 78, 79, 80, 81, 68,
69, 70, 71, 72, 73, 74, 75, 0, 76, 77,
- 78, 79, 80, 81, 101, 65, 66, 67, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 102,
+ 78, 79, 80, 81, 107, 65, 66, 67, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 108,
65, 66, 67, 0, 0, 0, 0, 68, 69, 70,
71, 72, 73, 74, 75, 0, 76, 77, 78, 79,
80, 81, 68, 69, 70, 71, 72, 73, 74, 75,
- 0, 76, 77, 78, 79, 80, 81, 103, 65, 66,
+ 0, 76, 77, 78, 79, 80, 81, 109, 65, 66,
67, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 104, 65, 66, 67, 0, 0, 0, 0,
+ 0, 0, 110, 65, 66, 67, 0, 0, 0, 0,
68, 69, 70, 71, 72, 73, 74, 75, 0, 76,
77, 78, 79, 80, 81, 68, 69, 70, 71, 72,
73, 74, 75, 0, 76, 77, 78, 79, 80, 81,
- 109, 65, 66, 67, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 110, 65, 66, 67, 0,
+ 114, 65, 66, 67, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 119, 65, 66, 67, 0,
0, 0, 0, 68, 69, 70, 71, 72, 73, 74,
75, 0, 76, 77, 78, 79, 80, 81, 68, 69,
70, 71, 72, 73, 74, 75, 0, 76, 77, 78,
- 79, 80, 81, 111, 65, 66, 67, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 112, 65,
- 66, 67, 0, 0, 0, 0, 68, 69, 70, 71,
- 72, 73, 74, 75, 0, 76, 77, 78, 79, 80,
- 81, 68, 69, 70, 71, 72, 73, 74, 75, 0,
- 76, 77, 78, 79, 80, 81, 113, 65, 66, 67,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 114, 65, 66, 67, 0, 0, 0, 0, 68,
- 69, 70, 71, 72, 73, 74, 75, 0, 76, 77,
- 78, 79, 80, 81, 68, 69, 70, 71, 72, 73,
- 74, 75, 0, 76, 77, 78, 79, 80, 81, 118,
- 65, 66, 67, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 123, 65, 66, 67, 0, 0,
- 0, 0, 68, 69, 70, 71, 72, 73, 74, 75,
- 0, 76, 77, 78, 79, 80, 81, 68, 69, 70,
- 71, 72, 73, 74, 75, 0, 76, 77, 78, 79,
- 80, 81, 124, 65, 66, 67, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 126, 65, 66,
- 67, 0, 0, 0, 0, 68, 69, 70, 71, 72,
- 73, 74, 75, 0, 76, 77, 78, 79, 80, 81,
- 68, 69, 70, 71, 72, 73, 74, 75, 0, 76,
- 77, 78, 79, 80, 81
+ 79, 80, 81
};
static const yytype_int8 yycheck[] =
{
- 38, 39, 40, 41, 3, 43, 27, 45, 46, 30,
- 48, 49, 32, 37, 32, 53, 54, 55, 56, 57,
- 58, 0, 1, 3, 3, 33, 29, 6, 7, 8,
+ 38, 39, 40, 41, 26, 43, 28, 27, 3, 32,
+ 30, 33, 37, 32, 29, 53, 54, 55, 56, 57,
+ 58, 0, 1, 3, 3, 33, 32, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23, 24, 25, 32, 30, 33,
- 33, 89, 33, 33, 28, 34, 35, 36, 37, 38,
- 39, 40, 3, 4, 5, 6, 26, 33, 28, 33,
- 33, 33, 33, 33, 33, 33, 33, -1, 116, 117,
- 3, 4, 5, 6, 122, 26, 27, 28, 29, 30,
+ 19, 20, 21, 22, 23, 24, 25, 33, 33, 33,
+ 33, 89, 3, 33, 3, 34, 35, 36, 37, 38,
+ 39, 40, 3, 4, 5, 6, 3, 3, 33, 33,
+ 33, 28, 33, 33, 33, 113, 30, 3, 4, 5,
+ 6, 3, 3, 33, -1, 26, 27, 28, 29, 30,
31, 32, 33, -1, 35, 36, 37, 38, 39, 40,
- -1, -1, -1, 26, 27, 28, 29, 30, 31, 32,
+ 26, 27, 28, 29, 30, 31, 32, 33, -1, 35,
+ 36, 37, 38, 39, 40, 3, 4, 5, 6, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 3, 4, 5, 6, -1, -1, -1, -1, 26, 27,
+ 28, 29, 30, 31, 32, 33, -1, 35, 36, 37,
+ 38, 39, 40, 26, 27, 28, 29, 30, 31, 32,
33, -1, 35, 36, 37, 38, 39, 40, 3, 4,
5, 6, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, 3, 4, 5, 6, -1, -1, -1,
@@ -822,28 +811,7 @@ static const yytype_int8 yycheck[] =
-1, -1, -1, 26, 27, 28, 29, 30, 31, 32,
33, -1, 35, 36, 37, 38, 39, 40, 26, 27,
28, 29, 30, 31, 32, 33, -1, 35, 36, 37,
- 38, 39, 40, 3, 4, 5, 6, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 3, 4,
- 5, 6, -1, -1, -1, -1, 26, 27, 28, 29,
- 30, 31, 32, 33, -1, 35, 36, 37, 38, 39,
- 40, 26, 27, 28, 29, 30, 31, 32, 33, -1,
- 35, 36, 37, 38, 39, 40, 3, 4, 5, 6,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 3, 4, 5, 6, -1, -1, -1, -1, 26,
- 27, 28, 29, 30, 31, 32, 33, -1, 35, 36,
- 37, 38, 39, 40, 26, 27, 28, 29, 30, 31,
- 32, 33, -1, 35, 36, 37, 38, 39, 40, 3,
- 4, 5, 6, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 3, 4, 5, 6, -1, -1,
- -1, -1, 26, 27, 28, 29, 30, 31, 32, 33,
- -1, 35, 36, 37, 38, 39, 40, 26, 27, 28,
- 29, 30, 31, 32, 33, -1, 35, 36, 37, 38,
- 39, 40, 3, 4, 5, 6, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 3, 4, 5,
- 6, -1, -1, -1, -1, 26, 27, 28, 29, 30,
- 31, 32, 33, -1, 35, 36, 37, 38, 39, 40,
- 26, 27, 28, 29, 30, 31, 32, 33, -1, 35,
- 36, 37, 38, 39, 40
+ 38, 39, 40
};
/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
@@ -858,11 +826,11 @@ static const yytype_int8 yystos[] =
29, 26, 28, 33, 32, 33, 33, 33, 33, 53,
53, 53, 53, 53, 3, 4, 5, 6, 26, 27,
28, 29, 30, 31, 32, 33, 35, 36, 37, 38,
- 39, 40, 54, 53, 53, 53, 53, 33, 33, 33,
+ 39, 40, 54, 3, 3, 3, 3, 33, 33, 33,
53, 53, 53, 53, 53, 53, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 27, 30, 28, 53, 3,
- 3, 3, 3, 3, 3, 33, 33, 33, 3, 30,
- 53, 53, 33, 3, 3, 53, 3
+ 3, 27, 30, 28, 53, 3, 3, 3, 3, 3,
+ 3, 33, 33, 33, 3, 30, 3, 53, 33, 3,
+ 3
};
/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */
@@ -880,8 +848,8 @@ static const yytype_int8 yyr1[] =
/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */
static const yytype_int8 yyr2[] =
{
- 0, 2, 0, 2, 2, 4, 4, 7, 9, 4,
- 4, 5, 7, 4, 4, 3, 4, 4, 4, 4,
+ 0, 2, 0, 2, 2, 4, 3, 6, 8, 3,
+ 3, 5, 7, 3, 4, 3, 4, 4, 4, 4,
4, 3, 3, 3, 3, 1, 2, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 2, 1, 1,
@@ -1361,19 +1329,19 @@ yydestruct (const char *yymsg,
case YYSYMBOL_STRING: /* STRING */
#line 100 "cmFortranParser.y"
{ free(((*yyvaluep).string)); }
-#line 1365 "cmFortranParser.cxx"
+#line 1333 "cmFortranParser.cxx"
break;
case YYSYMBOL_WORD: /* WORD */
#line 100 "cmFortranParser.y"
{ free(((*yyvaluep).string)); }
-#line 1371 "cmFortranParser.cxx"
+#line 1339 "cmFortranParser.cxx"
break;
case YYSYMBOL_CPP_INCLUDE_ANGLE: /* CPP_INCLUDE_ANGLE */
#line 100 "cmFortranParser.y"
{ free(((*yyvaluep).string)); }
-#line 1377 "cmFortranParser.cxx"
+#line 1345 "cmFortranParser.cxx"
break;
default:
@@ -1655,7 +1623,7 @@ yyreduce:
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_SetInInterface(parser, true);
}
-#line 1659 "cmFortranParser.cxx"
+#line 1627 "cmFortranParser.cxx"
break;
case 5: /* stmt: USE WORD other EOSTMT */
@@ -1665,77 +1633,73 @@ yyreduce:
cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1669 "cmFortranParser.cxx"
+#line 1637 "cmFortranParser.cxx"
break;
- case 6: /* stmt: MODULE WORD other EOSTMT */
+ case 6: /* stmt: MODULE WORD EOSTMT */
#line 118 "cmFortranParser.y"
- {
+ {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
- if (cmsysString_strcasecmp((yyvsp[-2].string), "function") != 0 &&
- cmsysString_strcasecmp((yyvsp[-2].string), "procedure") != 0 &&
- cmsysString_strcasecmp((yyvsp[-2].string), "subroutine") != 0) {
- cmFortranParser_RuleModule(parser, (yyvsp[-2].string));
- }
- free((yyvsp[-2].string));
+ cmFortranParser_RuleModule(parser, (yyvsp[-1].string));
+ free((yyvsp[-1].string));
}
-#line 1683 "cmFortranParser.cxx"
+#line 1647 "cmFortranParser.cxx"
break;
- case 7: /* stmt: SUBMODULE LPAREN WORD RPAREN WORD other EOSTMT */
-#line 127 "cmFortranParser.y"
- {
+ case 7: /* stmt: SUBMODULE LPAREN WORD RPAREN WORD EOSTMT */
+#line 123 "cmFortranParser.y"
+ {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
- cmFortranParser_RuleSubmodule(parser, (yyvsp[-4].string), (yyvsp[-2].string));
- free((yyvsp[-4].string));
- free((yyvsp[-2].string));
+ cmFortranParser_RuleSubmodule(parser, (yyvsp[-3].string), (yyvsp[-1].string));
+ free((yyvsp[-3].string));
+ free((yyvsp[-1].string));
}
-#line 1694 "cmFortranParser.cxx"
+#line 1658 "cmFortranParser.cxx"
break;
- case 8: /* stmt: SUBMODULE LPAREN WORD COLON WORD RPAREN WORD other EOSTMT */
-#line 133 "cmFortranParser.y"
- {
+ case 8: /* stmt: SUBMODULE LPAREN WORD COLON WORD RPAREN WORD EOSTMT */
+#line 129 "cmFortranParser.y"
+ {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
- cmFortranParser_RuleSubmoduleNested(parser, (yyvsp[-6].string), (yyvsp[-4].string), (yyvsp[-2].string));
- free((yyvsp[-6].string));
- free((yyvsp[-4].string));
- free((yyvsp[-2].string));
+ cmFortranParser_RuleSubmoduleNested(parser, (yyvsp[-5].string), (yyvsp[-3].string), (yyvsp[-1].string));
+ free((yyvsp[-5].string));
+ free((yyvsp[-3].string));
+ free((yyvsp[-1].string));
}
-#line 1706 "cmFortranParser.cxx"
+#line 1670 "cmFortranParser.cxx"
break;
- case 9: /* stmt: INTERFACE WORD other EOSTMT */
-#line 140 "cmFortranParser.y"
- {
+ case 9: /* stmt: INTERFACE WORD EOSTMT */
+#line 136 "cmFortranParser.y"
+ {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_SetInInterface(parser, true);
- free((yyvsp[-2].string));
+ free((yyvsp[-1].string));
}
-#line 1716 "cmFortranParser.cxx"
+#line 1680 "cmFortranParser.cxx"
break;
- case 10: /* stmt: END INTERFACE other EOSTMT */
-#line 145 "cmFortranParser.y"
- {
+ case 10: /* stmt: END INTERFACE EOSTMT */
+#line 141 "cmFortranParser.y"
+ {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_SetInInterface(parser, false);
}
-#line 1725 "cmFortranParser.cxx"
+#line 1689 "cmFortranParser.cxx"
break;
case 11: /* stmt: USE DCOLON WORD other EOSTMT */
-#line 149 "cmFortranParser.y"
+#line 145 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1735 "cmFortranParser.cxx"
+#line 1699 "cmFortranParser.cxx"
break;
case 12: /* stmt: USE COMMA WORD DCOLON WORD other EOSTMT */
-#line 154 "cmFortranParser.y"
+#line 150 "cmFortranParser.y"
{
if (cmsysString_strcasecmp((yyvsp[-4].string), "non_intrinsic") == 0) {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
@@ -1748,139 +1712,139 @@ yyreduce:
free((yyvsp[-4].string));
free((yyvsp[-2].string));
}
-#line 1752 "cmFortranParser.cxx"
+#line 1716 "cmFortranParser.cxx"
break;
- case 13: /* stmt: INCLUDE STRING other EOSTMT */
-#line 166 "cmFortranParser.y"
- {
+ case 13: /* stmt: INCLUDE STRING EOSTMT */
+#line 162 "cmFortranParser.y"
+ {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
- cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
- free((yyvsp[-2].string));
+ cmFortranParser_RuleInclude(parser, (yyvsp[-1].string));
+ free((yyvsp[-1].string));
}
-#line 1762 "cmFortranParser.cxx"
+#line 1726 "cmFortranParser.cxx"
break;
case 14: /* stmt: CPP_LINE_DIRECTIVE STRING other EOSTMT */
-#line 171 "cmFortranParser.y"
+#line 167 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleLineDirective(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1772 "cmFortranParser.cxx"
+#line 1736 "cmFortranParser.cxx"
break;
case 15: /* stmt: CPP_INCLUDE_ANGLE other EOSTMT */
-#line 176 "cmFortranParser.y"
+#line 172 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1782 "cmFortranParser.cxx"
+#line 1746 "cmFortranParser.cxx"
break;
case 16: /* stmt: include STRING other EOSTMT */
-#line 181 "cmFortranParser.y"
+#line 177 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1792 "cmFortranParser.cxx"
+#line 1756 "cmFortranParser.cxx"
break;
case 17: /* stmt: define WORD other EOSTMT */
-#line 186 "cmFortranParser.y"
+#line 182 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleDefine(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1802 "cmFortranParser.cxx"
+#line 1766 "cmFortranParser.cxx"
break;
case 18: /* stmt: undef WORD other EOSTMT */
-#line 191 "cmFortranParser.y"
+#line 187 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleUndef(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1812 "cmFortranParser.cxx"
+#line 1776 "cmFortranParser.cxx"
break;
case 19: /* stmt: ifdef WORD other EOSTMT */
-#line 196 "cmFortranParser.y"
+#line 192 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleIfdef(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1822 "cmFortranParser.cxx"
+#line 1786 "cmFortranParser.cxx"
break;
case 20: /* stmt: ifndef WORD other EOSTMT */
-#line 201 "cmFortranParser.y"
+#line 197 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleIfndef(parser, (yyvsp[-2].string));
free((yyvsp[-2].string));
}
-#line 1832 "cmFortranParser.cxx"
+#line 1796 "cmFortranParser.cxx"
break;
case 21: /* stmt: if other EOSTMT */
-#line 206 "cmFortranParser.y"
+#line 202 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleIf(parser);
}
-#line 1841 "cmFortranParser.cxx"
+#line 1805 "cmFortranParser.cxx"
break;
case 22: /* stmt: elif other EOSTMT */
-#line 210 "cmFortranParser.y"
+#line 206 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleElif(parser);
}
-#line 1850 "cmFortranParser.cxx"
+#line 1814 "cmFortranParser.cxx"
break;
case 23: /* stmt: else other EOSTMT */
-#line 214 "cmFortranParser.y"
+#line 210 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleElse(parser);
}
-#line 1859 "cmFortranParser.cxx"
+#line 1823 "cmFortranParser.cxx"
break;
case 24: /* stmt: endif other EOSTMT */
-#line 218 "cmFortranParser.y"
+#line 214 "cmFortranParser.y"
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleEndif(parser);
}
-#line 1868 "cmFortranParser.cxx"
+#line 1832 "cmFortranParser.cxx"
break;
case 48: /* misc_code: WORD */
-#line 240 "cmFortranParser.y"
+#line 236 "cmFortranParser.y"
{ free ((yyvsp[0].string)); }
-#line 1874 "cmFortranParser.cxx"
+#line 1838 "cmFortranParser.cxx"
break;
case 55: /* misc_code: STRING */
-#line 247 "cmFortranParser.y"
+#line 243 "cmFortranParser.y"
{ free ((yyvsp[0].string)); }
-#line 1880 "cmFortranParser.cxx"
+#line 1844 "cmFortranParser.cxx"
break;
-#line 1884 "cmFortranParser.cxx"
+#line 1848 "cmFortranParser.cxx"
default: break;
}
@@ -2104,6 +2068,6 @@ yyreturnlab:
return yyresult;
}
-#line 259 "cmFortranParser.y"
+#line 255 "cmFortranParser.y"
/* End of grammar */
diff --git a/Source/LexerParser/cmFortranParser.y b/Source/LexerParser/cmFortranParser.y
index 07ca630..a5c8976 100644
--- a/Source/LexerParser/cmFortranParser.y
+++ b/Source/LexerParser/cmFortranParser.y
@@ -115,34 +115,30 @@ stmt:
cmFortranParser_RuleUse(parser, $2);
free($2);
}
-| MODULE WORD other EOSTMT {
+| MODULE WORD EOSTMT {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
- if (cmsysString_strcasecmp($2, "function") != 0 &&
- cmsysString_strcasecmp($2, "procedure") != 0 &&
- cmsysString_strcasecmp($2, "subroutine") != 0) {
- cmFortranParser_RuleModule(parser, $2);
- }
+ cmFortranParser_RuleModule(parser, $2);
free($2);
}
-| SUBMODULE LPAREN WORD RPAREN WORD other EOSTMT {
+| SUBMODULE LPAREN WORD RPAREN WORD EOSTMT {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleSubmodule(parser, $3, $5);
free($3);
free($5);
}
-| SUBMODULE LPAREN WORD COLON WORD RPAREN WORD other EOSTMT {
+| SUBMODULE LPAREN WORD COLON WORD RPAREN WORD EOSTMT {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleSubmoduleNested(parser, $3, $5, $7);
free($3);
free($5);
free($7);
}
-| INTERFACE WORD other EOSTMT {
+| INTERFACE WORD EOSTMT {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_SetInInterface(parser, true);
free($2);
}
-| END INTERFACE other EOSTMT {
+| END INTERFACE EOSTMT {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_SetInInterface(parser, false);
}
@@ -163,7 +159,7 @@ stmt:
free($3);
free($5);
}
-| INCLUDE STRING other EOSTMT {
+| INCLUDE STRING EOSTMT {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleInclude(parser, $2);
free($2);
diff --git a/Source/Modules/CMakeBuildUtilities.cmake b/Source/Modules/CMakeBuildUtilities.cmake
new file mode 100644
index 0000000..5cfb0e7
--- /dev/null
+++ b/Source/Modules/CMakeBuildUtilities.cmake
@@ -0,0 +1,379 @@
+#-----------------------------------------------------------------------
+# Build the utilities used by CMake
+#
+# Originally it was a macro in the root `CMakeLists.txt` with the comment
+# "Simply to improve readability...".
+# However, as part of the modernization refactoring it was moved into a
+# separate file cuz adding library alises wasn't possible inside the
+# macro.
+#-----------------------------------------------------------------------
+
+# Suppress unnecessary checks in third-party code.
+include(Utilities/cmThirdPartyChecks.cmake)
+
+#---------------------------------------------------------------------
+# Create the kwsys library for CMake.
+set(KWSYS_NAMESPACE cmsys)
+set(KWSYS_USE_SystemTools 1)
+set(KWSYS_USE_Directory 1)
+set(KWSYS_USE_RegularExpression 1)
+set(KWSYS_USE_Base64 1)
+set(KWSYS_USE_MD5 1)
+set(KWSYS_USE_Process 1)
+set(KWSYS_USE_CommandLineArguments 1)
+set(KWSYS_USE_ConsoleBuf 1)
+set(KWSYS_HEADER_ROOT ${CMake_BINARY_DIR}/Source)
+set(KWSYS_INSTALL_DOC_DIR "${CMAKE_DOC_DIR}")
+if(CMake_NO_CXX_STANDARD)
+ set(KWSYS_CXX_STANDARD "")
+endif()
+if(CMake_NO_SELF_BACKTRACE)
+ set(KWSYS_NO_EXECINFO 1)
+endif()
+if(WIN32)
+ # FIXME: Teach KWSys to hard-code these checks on Windows.
+ set(KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC_COMPILED 0)
+ set(KWSYS_C_HAS_PTRDIFF_T_COMPILED 1)
+ set(KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H_COMPILED 1)
+ set(KWSYS_CXX_HAS_RLIMIT64_COMPILED 0)
+ set(KWSYS_CXX_HAS_SETENV_COMPILED 0)
+ set(KWSYS_CXX_HAS_UNSETENV_COMPILED 0)
+ set(KWSYS_CXX_HAS_UTIMENSAT_COMPILED 0)
+ set(KWSYS_CXX_HAS_UTIMES_COMPILED 0)
+ set(KWSYS_CXX_STAT_HAS_ST_MTIM_COMPILED 0)
+ set(KWSYS_CXX_STAT_HAS_ST_MTIMESPEC_COMPILED 0)
+ set(KWSYS_STL_HAS_WSTRING_COMPILED 1)
+ set(KWSYS_SYS_HAS_IFADDRS_H 0)
+endif()
+add_subdirectory(Source/kwsys)
+set(kwsys_folder "Utilities/KWSys")
+CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE} "${kwsys_folder}")
+CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}_c "${kwsys_folder}")
+if(BUILD_TESTING)
+ CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestDynload "${kwsys_folder}")
+ CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestProcess "${kwsys_folder}")
+ CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestsC "${kwsys_folder}")
+ CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestsCxx "${kwsys_folder}")
+ CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestSharedForward "${kwsys_folder}")
+endif()
+
+#---------------------------------------------------------------------
+# Setup third-party libraries.
+# Everything in the tree should be able to include files from the
+# Utilities directory.
+if((CMAKE_SYSTEM_NAME STREQUAL "AIX" OR CMAKE_SYSTEM_NAME STREQUAL "OS400") AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ # using -isystem option generate error "template with C linkage"
+ include_directories("${CMake_SOURCE_DIR}/Utilities/std")
+else()
+ include_directories(SYSTEM "${CMake_SOURCE_DIR}/Utilities/std")
+endif()
+
+include_directories("${CMake_BINARY_DIR}/Utilities")
+if((CMAKE_SYSTEM_NAME STREQUAL "AIX" OR CMAKE_SYSTEM_NAME STREQUAL "OS400") AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ # using -isystem option generate error "template with C linkage"
+ include_directories("${CMake_SOURCE_DIR}/Utilities")
+else()
+ include_directories(SYSTEM "${CMake_SOURCE_DIR}/Utilities")
+endif()
+
+#---------------------------------------------------------------------
+# Build CMake std library for CMake and CTest.
+add_subdirectory(Utilities/std)
+CMAKE_SET_TARGET_FOLDER(cmstd "Utilities/std")
+
+# check for the use of system libraries versus builtin ones
+# (a macro defined in this file)
+CMAKE_HANDLE_SYSTEM_LIBRARIES()
+
+if(CMAKE_USE_SYSTEM_KWIML)
+ find_package(KWIML 1.0)
+ if(NOT KWIML_FOUND)
+ message(FATAL_ERROR "CMAKE_USE_SYSTEM_KWIML is ON but KWIML is not found!")
+ endif()
+else()
+ if(BUILD_TESTING)
+ set(KWIML_TEST_ENABLE 1)
+ endif()
+ add_subdirectory(Utilities/KWIML)
+endif()
+
+if(CMAKE_USE_SYSTEM_LIBRHASH)
+ find_package(LibRHash)
+ if(NOT LibRHash_FOUND)
+ message(FATAL_ERROR
+ "CMAKE_USE_SYSTEM_LIBRHASH is ON but LibRHash is not found!")
+ endif()
+else()
+ add_subdirectory(Utilities/cmlibrhash)
+ add_library(LibRHash::LibRHash ALIAS cmlibrhash)
+ CMAKE_SET_TARGET_FOLDER(cmlibrhash "Utilities/3rdParty")
+endif()
+
+#---------------------------------------------------------------------
+# Build zlib library for Curl, CMake, and CTest.
+if(CMAKE_USE_SYSTEM_ZLIB)
+ find_package(ZLIB)
+ if(NOT ZLIB_FOUND)
+ message(FATAL_ERROR
+ "CMAKE_USE_SYSTEM_ZLIB is ON but a zlib is not found!")
+ endif()
+else()
+ if(NOT POLICY CMP0102) # CMake < 3.17
+ # Store in cache to protect from mark_as_advanced.
+ set(ZLIB_INCLUDE_DIR ${CMake_SOURCE_DIR}/Utilities CACHE PATH "")
+ else()
+ set(ZLIB_INCLUDE_DIR ${CMake_SOURCE_DIR}/Utilities)
+ endif()
+ set(ZLIB_LIBRARY cmzlib)
+ set(WITHOUT_ZLIB_DLL "")
+ set(WITHOUT_ZLIB_DLL_WITH_LIB cmzlib)
+ set(ZLIB_DLL "")
+ set(ZLIB_DLL_WITH_LIB cmzlib)
+ set(ZLIB_WINAPI "")
+ set(ZLIB_WINAPI_COMPILED 0)
+ set(ZLIB_WINAPI_WITH_LIB cmzlib)
+ add_subdirectory(Utilities/cmzlib)
+ add_library(ZLIB::ZLIB ALIAS cmzlib)
+ CMAKE_SET_TARGET_FOLDER(cmzlib "Utilities/3rdParty")
+endif()
+
+#---------------------------------------------------------------------
+# Build Curl library for CTest.
+if(CMAKE_USE_SYSTEM_CURL)
+ find_package(CURL)
+ if(NOT CURL_FOUND)
+ message(FATAL_ERROR
+ "CMAKE_USE_SYSTEM_CURL is ON but a curl is not found!")
+ endif()
+else()
+ if(CMAKE_TESTS_CDASH_SERVER)
+ set(CMAKE_CURL_TEST_URL "${CMAKE_TESTS_CDASH_SERVER}/user.php")
+ endif()
+ set(_CMAKE_USE_OPENSSL_DEFAULT OFF)
+ if(NOT DEFINED CMAKE_USE_OPENSSL AND NOT WIN32 AND NOT APPLE
+ AND CMAKE_SYSTEM_NAME MATCHES "(Linux|FreeBSD)")
+ set(_CMAKE_USE_OPENSSL_DEFAULT ON)
+ endif()
+ option(CMAKE_USE_OPENSSL "Use OpenSSL." ${_CMAKE_USE_OPENSSL_DEFAULT})
+ mark_as_advanced(CMAKE_USE_OPENSSL)
+ if(CMAKE_USE_OPENSSL)
+ set(CURL_CA_BUNDLE "" CACHE FILEPATH "Path to SSL CA Certificate Bundle")
+ set(CURL_CA_PATH "" CACHE PATH "Path to SSL CA Certificate Directory")
+ mark_as_advanced(CURL_CA_BUNDLE CURL_CA_PATH)
+ endif()
+ if(NOT CMAKE_USE_SYSTEM_NGHTTP2)
+ # Tell curl's FindNGHTTP2 module to use our library.
+ set(NGHTTP2_LIBRARY cmnghttp2)
+ set(NGHTTP2_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/cmnghttp2/lib/includes)
+ endif()
+ add_subdirectory(Utilities/cmcurl)
+ add_library(CURL::libcurl ALIAS cmcurl)
+ CMAKE_SET_TARGET_FOLDER(cmcurl "Utilities/3rdParty")
+ CMAKE_SET_TARGET_FOLDER(LIBCURL "Utilities/3rdParty")
+ if(NOT CMAKE_USE_SYSTEM_NGHTTP2)
+ # Configure after curl to re-use some check results.
+ add_subdirectory(Utilities/cmnghttp2)
+ CMAKE_SET_TARGET_FOLDER(cmnghttp2 "Utilities/3rdParty")
+ endif()
+endif()
+
+#---------------------------------------------------------------------
+# Build expat library for CMake, CTest, and libarchive.
+if(CMAKE_USE_SYSTEM_EXPAT)
+ find_package(EXPAT)
+ if(NOT EXPAT_FOUND)
+ message(FATAL_ERROR
+ "CMAKE_USE_SYSTEM_EXPAT is ON but a expat is not found!")
+ endif()
+ set(CMAKE_EXPAT_INCLUDES ${EXPAT_INCLUDE_DIRS})
+ set(CMAKE_EXPAT_LIBRARIES ${EXPAT_LIBRARIES})
+else()
+ set(CMAKE_EXPAT_INCLUDES)
+ set(CMAKE_EXPAT_LIBRARIES cmexpat)
+ add_subdirectory(Utilities/cmexpat)
+ add_library(EXPAT::EXPAT ALIAS cmexpat)
+ CMAKE_SET_TARGET_FOLDER(cmexpat "Utilities/3rdParty")
+endif()
+
+#---------------------------------------------------------------------
+# Build or use system libbz2 for libarchive.
+if(NOT CMAKE_USE_SYSTEM_LIBARCHIVE)
+ if(CMAKE_USE_SYSTEM_BZIP2)
+ find_package(BZip2)
+ else()
+ set(BZIP2_INCLUDE_DIR
+ "${CMAKE_CURRENT_SOURCE_DIR}/Utilities/cmbzip2")
+ set(BZIP2_LIBRARIES cmbzip2)
+ set(BZIP2_NEED_PREFIX "")
+ set(USE_BZIP2_DLL "")
+ set(USE_BZIP2_DLL_WITH_LIB cmbzip2)
+ set(USE_BZIP2_STATIC "")
+ set(USE_BZIP2_STATIC_WITH_LIB cmbzip2)
+ add_subdirectory(Utilities/cmbzip2)
+ CMAKE_SET_TARGET_FOLDER(cmbzip2 "Utilities/3rdParty")
+ endif()
+endif()
+
+#---------------------------------------------------------------------
+# Build or use system zstd for libarchive.
+if(NOT CMAKE_USE_SYSTEM_LIBARCHIVE)
+ if(NOT CMAKE_USE_SYSTEM_ZSTD)
+ set(ZSTD_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Utilities/cmzstd")
+ set(ZSTD_LIBRARY cmzstd)
+ add_subdirectory(Utilities/cmzstd)
+ CMAKE_SET_TARGET_FOLDER(cmzstd "Utilities/3rdParty")
+ endif()
+endif()
+
+#---------------------------------------------------------------------
+# Build or use system liblzma for libarchive.
+if(NOT CMAKE_USE_SYSTEM_LIBARCHIVE)
+ if(CMAKE_USE_SYSTEM_LIBLZMA)
+ find_package(LibLZMA)
+ if(NOT LIBLZMA_FOUND)
+ message(FATAL_ERROR "CMAKE_USE_SYSTEM_LIBLZMA is ON but LibLZMA is not found!")
+ endif()
+ else()
+ add_subdirectory(Utilities/cmliblzma)
+ CMAKE_SET_TARGET_FOLDER(cmliblzma "Utilities/3rdParty")
+ set(LIBLZMA_HAS_AUTO_DECODER 1)
+ set(LIBLZMA_HAS_EASY_ENCODER 1)
+ set(LIBLZMA_HAS_LZMA_PRESET 1)
+ set(LIBLZMA_INCLUDE_DIR
+ "${CMAKE_CURRENT_SOURCE_DIR}/Utilities/cmliblzma/liblzma/api")
+ set(LIBLZMA_LIBRARY cmliblzma)
+ set(HAVE_LZMA_STREAM_ENCODER_MT 1)
+ endif()
+endif()
+
+#---------------------------------------------------------------------
+# Build or use system libarchive for CMake and CTest.
+if(CMAKE_USE_SYSTEM_LIBARCHIVE)
+ find_package(LibArchive 3.3.3)
+ if(NOT LibArchive_FOUND)
+ message(FATAL_ERROR "CMAKE_USE_SYSTEM_LIBARCHIVE is ON but LibArchive is not found!")
+ endif()
+ # NOTE `FindLibArchive` got imported targets support since 3.17
+ if (NOT TARGET LibArchive::LibArchive)
+ add_library(LibArchive::LibArchive UNKNOWN IMPORTED)
+ set_target_properties(LibArchive::LibArchive PROPERTIES
+ IMPORTED_LOCATION "${LibArchive_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES "${LibArchive_INCLUDE_DIRS}")
+ endif ()
+else()
+ set(EXPAT_INCLUDE_DIR ${CMAKE_EXPAT_INCLUDES})
+ set(EXPAT_LIBRARY ${CMAKE_EXPAT_LIBRARIES})
+ set(ENABLE_MBEDTLS OFF)
+ set(ENABLE_NETTLE OFF)
+ if(DEFINED CMAKE_USE_OPENSSL)
+ set(ENABLE_OPENSSL "${CMAKE_USE_OPENSSL}")
+ else()
+ set(ENABLE_OPENSSL OFF)
+ endif()
+ set(ENABLE_LIBB2 OFF)
+ set(ENABLE_LZ4 OFF)
+ set(ENABLE_LZO OFF)
+ set(ENABLE_LZMA ON)
+ set(ENABLE_ZSTD ON)
+ set(ENABLE_ZLIB ON)
+ set(ENABLE_BZip2 ON)
+ set(ENABLE_LIBXML2 OFF)
+ set(ENABLE_EXPAT OFF)
+ set(ENABLE_PCREPOSIX OFF)
+ set(ENABLE_LibGCC OFF)
+ set(ENABLE_CNG OFF)
+ set(ENABLE_TAR OFF)
+ set(ENABLE_TAR_SHARED OFF)
+ set(ENABLE_CPIO OFF)
+ set(ENABLE_CPIO_SHARED OFF)
+ set(ENABLE_CAT OFF)
+ set(ENABLE_CAT_SHARED OFF)
+ set(ENABLE_XATTR OFF)
+ set(ENABLE_ACL OFF)
+ set(ENABLE_ICONV OFF)
+ set(ENABLE_TEST OFF)
+ set(ENABLE_COVERAGE OFF)
+ set(ENABLE_INSTALL OFF)
+ set(POSIX_REGEX_LIB "" CACHE INTERNAL "libarchive: No POSIX regular expression support")
+ set(ENABLE_SAFESEH "" CACHE INTERNAL "libarchive: No /SAFESEH linker flag")
+ set(WINDOWS_VERSION "WIN7" CACHE INTERNAL "libarchive: Set Windows version to use (Windows only)")
+ add_subdirectory(Utilities/cmlibarchive)
+ add_library(LibArchive::LibArchive ALIAS cmlibarchive)
+ target_compile_definitions(cmlibarchive INTERFACE LIBARCHIVE_STATIC)
+ CMAKE_SET_TARGET_FOLDER(cmlibarchive "Utilities/3rdParty")
+endif()
+
+#---------------------------------------------------------------------
+# Build jsoncpp library.
+if(CMAKE_USE_SYSTEM_JSONCPP)
+ find_package(JsonCpp 1.6.0)
+ if(NOT JsonCpp_FOUND)
+ message(FATAL_ERROR
+ "CMAKE_USE_SYSTEM_JSONCPP is ON but a JsonCpp is not found!")
+ endif()
+ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|LCC|Clang")
+ set_property(TARGET JsonCpp::JsonCpp APPEND PROPERTY
+ INTERFACE_COMPILE_OPTIONS -Wno-deprecated-declarations)
+ endif()
+else()
+ add_subdirectory(Utilities/cmjsoncpp)
+ add_library(JsonCpp::JsonCpp ALIAS cmjsoncpp)
+ CMAKE_SET_TARGET_FOLDER(cmjsoncpp "Utilities/3rdParty")
+endif()
+
+#---------------------------------------------------------------------
+# Build libuv library.
+if(CMAKE_USE_SYSTEM_LIBUV)
+ if(WIN32)
+ find_package(LibUV 1.38.0)
+ else()
+ find_package(LibUV 1.28.0)
+ endif()
+ if(NOT LIBUV_FOUND)
+ message(FATAL_ERROR
+ "CMAKE_USE_SYSTEM_LIBUV is ON but a libuv is not found!")
+ endif()
+else()
+ add_subdirectory(Utilities/cmlibuv)
+ add_library(LibUV::LibUV ALIAS cmlibuv)
+ CMAKE_SET_TARGET_FOLDER(cmlibuv "Utilities/3rdParty")
+endif()
+
+#---------------------------------------------------------------------
+# Use curses?
+if(NOT DEFINED BUILD_CursesDialog)
+ if(UNIX)
+ include(${CMake_SOURCE_DIR}/Source/Checks/Curses.cmake)
+ set(BUILD_CursesDialog_DEFAULT "${CMakeCheckCurses_COMPILED}")
+ elseif(WIN32)
+ set(BUILD_CursesDialog_DEFAULT "OFF")
+ endif()
+ option(BUILD_CursesDialog "Build the CMake Curses Dialog ccmake" "${BUILD_CursesDialog_DEFAULT}")
+endif()
+if(BUILD_CursesDialog)
+ if(UNIX)
+ set(CURSES_NEED_NCURSES TRUE)
+ find_package(Curses)
+ if(NOT CURSES_FOUND)
+ message(WARNING
+ "'ccmake' will not be built because Curses was not found.\n"
+ "Turn off BUILD_CursesDialog to suppress this message."
+ )
+ set(BUILD_CursesDialog 0)
+ endif()
+ elseif(WIN32)
+ # FIXME: Add support for system-provided pdcurses.
+ add_subdirectory(Utilities/cmpdcurses)
+ set(CURSES_LIBRARY cmpdcurses)
+ set(CURSES_INCLUDE_PATH "") # cmpdcurses has usage requirements
+ set(CMAKE_USE_SYSTEM_FORM 0)
+ set(HAVE_CURSES_USE_DEFAULT_COLORS 1)
+ endif()
+endif()
+if(BUILD_CursesDialog)
+ if(NOT CMAKE_USE_SYSTEM_FORM)
+ add_subdirectory(Source/CursesDialog/form)
+ elseif(NOT CURSES_FORM_LIBRARY)
+ message(FATAL_ERROR "CMAKE_USE_SYSTEM_FORM in ON but CURSES_FORM_LIBRARY is not set!")
+ endif()
+endif()
diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt
index 0c263bb..989a929 100644
--- a/Source/QtDialog/CMakeLists.txt
+++ b/Source/QtDialog/CMakeLists.txt
@@ -3,7 +3,7 @@
project(QtDialog)
CMake_OPTIONAL_COMPONENT(cmake-gui)
-set (QT_COMPONENTS
+set(QT_COMPONENTS
Core
Widgets
Gui
@@ -41,8 +41,8 @@ set(CMake_QT_EXTRA_LIBRARIES)
# Try to find the package WinExtras for the task bar progress
if(WIN32)
find_package(Qt${INSTALLED_QT_VERSION}WinExtras QUIET)
- if (Qt${INSTALLED_QT_VERSION}WinExtras_FOUND)
- add_definitions(-DQT_WINEXTRAS)
+ if(Qt${INSTALLED_QT_VERSION}WinExtras_FOUND)
+ add_compile_definitions(QT_WINEXTRAS)
list(APPEND CMake_QT_EXTRA_LIBRARIES Qt${INSTALLED_QT_VERSION}::WinExtras)
list(APPEND QT_COMPONENTS WinExtras)
endif()
@@ -100,14 +100,14 @@ if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32))
endif()
endmacro()
macro(install_qt_plugins _comps _plugins_var)
- foreach(_qt_comp ${${_comps}})
- if (INSTALLED_QT_VERSION VERSION_LESS 6)
+ foreach(_qt_comp IN LISTS ${_comps})
+ if(INSTALLED_QT_VERSION VERSION_LESS 6)
set(_qt_module_plugins ${Qt${INSTALLED_QT_VERSION}${_qt_comp}_PLUGINS})
else()
get_target_property(_qt_module_plugins Qt${INSTALLED_QT_VERSION}::${_qt_comp} QT_PLUGINS)
endif()
- foreach(_qt_plugin ${_qt_module_plugins})
- if (INSTALLED_QT_VERSION VERSION_GREATER_EQUAL 6)
+ foreach(_qt_plugin IN LISTS _qt_module_plugins)
+ if(INSTALLED_QT_VERSION VERSION_GREATER_EQUAL 6)
# Qt6 provides the plugins as individual packages that need to be found.
find_package(Qt${INSTALLED_QT_VERSION}${_qt_plugin} QUIET
PATHS ${Qt${INSTALLED_QT_VERSION}${_qt_comp}_DIR})
@@ -117,7 +117,7 @@ if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32))
endforeach()
endmacro()
if(APPLE)
- if (INSTALLED_QT_VERSION VERSION_EQUAL 5)
+ if(INSTALLED_QT_VERSION VERSION_EQUAL 5)
install_qt_plugin("Qt5::QCocoaIntegrationPlugin" QT_PLUGINS)
if(TARGET Qt5::QMacStylePlugin)
install_qt_plugin("Qt5::QMacStylePlugin" QT_PLUGINS)
@@ -132,7 +132,7 @@ if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32))
DESTINATION "${CMAKE_INSTALL_PREFIX}/Resources"
${COMPONENT})
elseif(WIN32 AND NOT CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES)
- if (INSTALLED_QT_VERSION VERSION_EQUAL 5)
+ if(INSTALLED_QT_VERSION VERSION_EQUAL 5)
install_qt_plugin("Qt5::QWindowsIntegrationPlugin" QT_PLUGINS)
else()
# FIXME: Minimize plugins for Qt6.
@@ -152,7 +152,10 @@ if(APPLE)
get_filename_component(Qt_BIN_DIR "${Qt_BIN_DIR}" PATH)
endif()
-set(SRCS
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_library(
+ CMakeGUILib STATIC
AddCacheEntry.cxx
AddCacheEntry.h
CMakeSetupDialog.cxx
@@ -179,6 +182,16 @@ set(SRCS
WarningMessagesDialog.cxx
WarningMessagesDialog.h
)
+# CMake_QT_EXTRA_LIBRARIES have to come before the main libraries on the link line
+target_link_libraries(
+ CMakeGUILib
+ PUBLIC
+ CMakeLib
+ ${CMake_QT_EXTRA_LIBRARIES}
+ Qt${INSTALLED_QT_VERSION}::Core
+ Qt${INSTALLED_QT_VERSION}::Widgets
+ )
+
set(UI_SRCS
CMakeSetupDialog.ui
Compilers.ui
@@ -204,7 +217,7 @@ set(MOC_SRCS
)
set(QRC_SRCS CMakeSetup.qrc)
-if (INSTALLED_QT_VERSION VERSION_LESS 6)
+if(INSTALLED_QT_VERSION VERSION_LESS 6)
qt5_wrap_ui(UI_BUILT_SRCS ${UI_SRCS})
qt5_wrap_cpp(MOC_BUILT_SRCS ${MOC_SRCS})
qt5_add_resources(QRC_BUILT_SRCS ${QRC_SRCS})
@@ -215,15 +228,18 @@ else()
endif()
add_library(CMakeGUIQRCLib OBJECT ${QRC_BUILT_SRCS})
-if (FALSE) # CMake's bootstrap binary does not support automoc
+if(FALSE) # CMake's bootstrap binary does not support automoc
set(CMAKE_AUTOMOC 1)
set(CMAKE_AUTORCC 1)
set(CMAKE_AUTOUIC 1)
-else ()
- list(APPEND SRCS
- ${UI_BUILT_SRCS}
- ${MOC_BUILT_SRCS})
-endif ()
+else()
+ target_sources(
+ CMakeGUILib
+ PUBLIC
+ ${UI_BUILT_SRCS}
+ ${MOC_BUILT_SRCS}
+ )
+endif()
if(USE_LGPL)
install(FILES ${CMake_SOURCE_DIR}/Licenses/LGPLv${USE_LGPL}.txt
@@ -233,22 +249,20 @@ if(USE_LGPL)
PROPERTY COMPILE_DEFINITIONS USE_LGPL="${USE_LGPL}")
endif()
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
-add_library(CMakeGUILib STATIC ${SRCS})
-# CMake_QT_EXTRA_LIBRARIES have to come before the main libraries on the link line
-target_link_libraries(CMakeGUILib PUBLIC CMakeLib ${CMake_QT_EXTRA_LIBRARIES}
- Qt${INSTALLED_QT_VERSION}::Core Qt${INSTALLED_QT_VERSION}::Widgets)
-
add_library(CMakeGUIMainLib STATIC CMakeSetup.cxx)
-target_link_libraries(CMakeGUIMainLib PUBLIC CMakeGUILib)
+target_link_libraries(
+ CMakeGUIMainLib
+ PUBLIC
+ CMakeGUILib
+ CMakeGUIQRCLib
+ $<TARGET_NAME_IF_EXISTS:CMakeVersion>
+ )
-add_executable(cmake-gui WIN32 MACOSX_BUNDLE CMakeGUIExec.cxx ${MANIFEST_FILE})
-target_link_libraries(cmake-gui CMakeGUIMainLib Qt${INSTALLED_QT_VERSION}::Core)
+add_executable(cmake-gui WIN32 MACOSX_BUNDLE CMakeGUIExec.cxx)
+target_link_libraries(cmake-gui CMakeGUIMainLib ManifestLib Qt${INSTALLED_QT_VERSION}::Core)
-target_sources(CMakeGUIMainLib INTERFACE $<TARGET_OBJECTS:CMakeGUIQRCLib>)
if(WIN32)
- target_sources(CMakeGUIMainLib INTERFACE $<TARGET_OBJECTS:CMakeVersion> CMakeSetup.rc)
+ target_sources(CMakeGUIMainLib INTERFACE CMakeSetup.rc)
endif()
if(APPLE)
target_sources(CMakeGUIMainLib INTERFACE CMakeSetup.icns)
@@ -300,21 +314,19 @@ if(APPLE)
$<TARGET_FILE_DIR:cmake>/cmake-gui
)
endif()
-set(CMAKE_INSTALL_DESTINATION_ARGS
- BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}" ${COMPONENT})
install(TARGETS cmake-gui
RUNTIME DESTINATION bin ${COMPONENT}
- ${CMAKE_INSTALL_DESTINATION_ARGS})
+ BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}" ${COMPONENT})
if(UNIX AND NOT APPLE)
- foreach (size IN ITEMS 32 128)
+ foreach(size IN ITEMS 32 128)
install(
FILES "${CMAKE_CURRENT_SOURCE_DIR}/CMakeSetup${size}.png"
DESTINATION "${CMAKE_XDGDATA_DIR}/icons/hicolor/${size}x${size}/apps"
${COMPONENT}
RENAME "CMakeSetup.png")
- endforeach ()
+ endforeach()
# install a desktop file so CMake appears in the application start menu
# with an icon
@@ -348,5 +360,4 @@ if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32))
endif()
set(CMAKE_PACKAGE_QTGUI TRUE)
-configure_file("${QtDialog_SOURCE_DIR}/QtDialogCPack.cmake.in"
- "${QtDialog_BINARY_DIR}/QtDialogCPack.cmake" @ONLY)
+configure_file(QtDialogCPack.cmake.in QtDialogCPack.cmake @ONLY)
diff --git a/Source/QtDialog/FirstConfigure.cxx b/Source/QtDialog/FirstConfigure.cxx
index f3c4a8b..707eaae 100644
--- a/Source/QtDialog/FirstConfigure.cxx
+++ b/Source/QtDialog/FirstConfigure.cxx
@@ -244,7 +244,8 @@ void StartCompilerSetup::onGeneratorChanged(int index)
if (!DefaultGeneratorPlatform.isEmpty()) {
int platform_index = platforms.indexOf(DefaultGeneratorPlatform);
if (platform_index != -1) {
- this->PlatformOptions->setCurrentIndex(platform_index);
+ // The index is off-by-one due to the first empty item added above.
+ this->PlatformOptions->setCurrentIndex(platform_index + 1);
}
}
} else {
diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx
index 4624f1c..ad57a88 100644
--- a/Source/cmArgumentParser.cxx
+++ b/Source/cmArgumentParser.cxx
@@ -4,9 +4,14 @@
#include <algorithm>
+#include "cmArgumentParserTypes.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmStringAlgorithms.h"
+
namespace ArgumentParser {
-auto ActionMap::Emplace(cm::string_view name, Action action)
+auto KeywordActionMap::Emplace(cm::string_view name, KeywordAction action)
-> std::pair<iterator, bool>
{
auto const it =
@@ -19,7 +24,7 @@ auto ActionMap::Emplace(cm::string_view name, Action action)
: std::make_pair(this->emplace(it, name, std::move(action)), true);
}
-auto ActionMap::Find(cm::string_view name) const -> const_iterator
+auto KeywordActionMap::Find(cm::string_view name) const -> const_iterator
{
auto const it =
std::lower_bound(this->begin(), this->end(), name,
@@ -29,68 +34,171 @@ auto ActionMap::Find(cm::string_view name) const -> const_iterator
return (it != this->end() && it->first == name) ? it : this->end();
}
+auto PositionActionMap::Emplace(std::size_t pos, PositionAction action)
+ -> std::pair<iterator, bool>
+{
+ auto const it = std::lower_bound(
+ this->begin(), this->end(), pos,
+ [](value_type const& elem, std::size_t k) { return elem.first < k; });
+ return (it != this->end() && it->first == pos)
+ ? std::make_pair(it, false)
+ : std::make_pair(this->emplace(it, pos, std::move(action)), true);
+}
+
+auto PositionActionMap::Find(std::size_t pos) const -> const_iterator
+{
+ auto const it = std::lower_bound(
+ this->begin(), this->end(), pos,
+ [](value_type const& elem, std::size_t k) { return elem.first < k; });
+ return (it != this->end() && it->first == pos) ? it : this->end();
+}
+
+void Instance::Bind(std::function<Continue(cm::string_view)> f,
+ ExpectAtLeast expect)
+{
+ this->KeywordValueFunc = std::move(f);
+ this->KeywordValuesExpected = expect.Count;
+}
+
void Instance::Bind(bool& val)
{
val = true;
- this->CurrentString = nullptr;
- this->CurrentList = nullptr;
- this->ExpectValue = false;
+ this->Bind(nullptr, ExpectAtLeast{ 0 });
}
void Instance::Bind(std::string& val)
{
- this->CurrentString = &val;
- this->CurrentList = nullptr;
- this->ExpectValue = true;
+ this->Bind(
+ [&val](cm::string_view arg) -> Continue {
+ val = std::string(arg);
+ return Continue::No;
+ },
+ ExpectAtLeast{ 1 });
+}
+
+void Instance::Bind(NonEmpty<std::string>& val)
+{
+ this->Bind(
+ [this, &val](cm::string_view arg) -> Continue {
+ if (arg.empty() && this->ParseResults) {
+ this->ParseResults->AddKeywordError(this->Keyword,
+ " empty string not allowed\n");
+ }
+ val.assign(std::string(arg));
+ return Continue::No;
+ },
+ ExpectAtLeast{ 1 });
}
-void Instance::Bind(StringList& val)
+void Instance::Bind(Maybe<std::string>& val)
{
- this->CurrentString = nullptr;
- this->CurrentList = &val;
- this->ExpectValue = true;
+ this->Bind(
+ [&val](cm::string_view arg) -> Continue {
+ static_cast<std::string&>(val) = std::string(arg);
+ return Continue::No;
+ },
+ ExpectAtLeast{ 0 });
}
-void Instance::Bind(MultiStringList& val)
+void Instance::Bind(MaybeEmpty<std::vector<std::string>>& val)
{
- this->CurrentString = nullptr;
- this->CurrentList = (static_cast<void>(val.emplace_back()), &val.back());
- this->ExpectValue = false;
+ this->Bind(
+ [&val](cm::string_view arg) -> Continue {
+ val.emplace_back(arg);
+ return Continue::Yes;
+ },
+ ExpectAtLeast{ 0 });
}
-void Instance::Consume(cm::string_view arg, void* result,
- std::vector<std::string>* unparsedArguments,
- std::vector<std::string>* keywordsMissingValue,
- std::vector<std::string>* parsedKeywords)
+void Instance::Bind(NonEmpty<std::vector<std::string>>& val)
{
- auto const it = this->Bindings.Find(arg);
- if (it != this->Bindings.end()) {
- if (parsedKeywords != nullptr) {
- parsedKeywords->emplace_back(arg);
+ this->Bind(
+ [&val](cm::string_view arg) -> Continue {
+ val.emplace_back(arg);
+ return Continue::Yes;
+ },
+ ExpectAtLeast{ 1 });
+}
+
+void Instance::Bind(std::vector<std::vector<std::string>>& multiVal)
+{
+ multiVal.emplace_back();
+ std::vector<std::string>& val = multiVal.back();
+ this->Bind(
+ [&val](cm::string_view arg) -> Continue {
+ val.emplace_back(arg);
+ return Continue::Yes;
+ },
+ ExpectAtLeast{ 0 });
+}
+
+void Instance::Consume(std::size_t pos, cm::string_view arg)
+{
+ auto const it = this->Bindings.Keywords.Find(arg);
+ if (it != this->Bindings.Keywords.end()) {
+ this->FinishKeyword();
+ this->Keyword = it->first;
+ this->KeywordValuesSeen = 0;
+ this->DoneWithPositional = true;
+ if (this->Bindings.ParsedKeyword) {
+ this->Bindings.ParsedKeyword(*this, it->first);
}
- it->second(*this, result);
- if (this->ExpectValue && keywordsMissingValue != nullptr) {
- keywordsMissingValue->emplace_back(arg);
+ it->second(*this);
+ return;
+ }
+
+ if (this->KeywordValueFunc) {
+ switch (this->KeywordValueFunc(arg)) {
+ case Continue::Yes:
+ break;
+ case Continue::No:
+ this->KeywordValueFunc = nullptr;
+ break;
}
+ ++this->KeywordValuesSeen;
return;
}
- if (this->CurrentString != nullptr) {
- this->CurrentString->assign(std::string(arg));
- this->CurrentString = nullptr;
- this->CurrentList = nullptr;
- } else if (this->CurrentList != nullptr) {
- this->CurrentList->emplace_back(arg);
- } else if (unparsedArguments != nullptr) {
- unparsedArguments->emplace_back(arg);
+ if (!this->DoneWithPositional) {
+ auto const pit = this->Bindings.Positions.Find(pos);
+ if (pit != this->Bindings.Positions.end()) {
+ pit->second(*this, pos, arg);
+ return;
+ }
+ }
+
+ if (this->UnparsedArguments != nullptr) {
+ this->UnparsedArguments->emplace_back(arg);
}
+}
- if (this->ExpectValue) {
- if (keywordsMissingValue != nullptr) {
- keywordsMissingValue->pop_back();
+void Instance::FinishKeyword()
+{
+ if (this->Keyword.empty()) {
+ return;
+ }
+ if (this->KeywordValuesSeen < this->KeywordValuesExpected) {
+ if (this->ParseResults != nullptr) {
+ this->ParseResults->AddKeywordError(this->Keyword,
+ " missing required value\n");
}
- this->ExpectValue = false;
+ if (this->Bindings.KeywordMissingValue) {
+ this->Bindings.KeywordMissingValue(*this, this->Keyword);
+ }
+ }
+}
+
+bool ParseResult::MaybeReportError(cmMakefile& mf) const
+{
+ if (*this) {
+ return false;
+ }
+ std::string e;
+ for (auto const& ke : this->KeywordErrors) {
+ e = cmStrCat(e, "Error after keyword \"", ke.first, "\":\n", ke.second);
}
+ mf.IssueMessage(MessageType::FATAL_ERROR, e);
+ return true;
}
} // namespace ArgumentParser
diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h
index 71ed844..fdf54fb 100644
--- a/Source/cmArgumentParser.h
+++ b/Source/cmArgumentParser.h
@@ -5,59 +5,220 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <cassert>
+#include <cstddef>
#include <functional>
+#include <map>
#include <string>
#include <utility>
#include <vector>
+#include <cm/optional>
#include <cm/string_view>
+#include <cm/type_traits>
#include <cmext/string_view>
+#include "cmArgumentParserTypes.h" // IWYU pragma: keep
+
+template <typename Result>
+class cmArgumentParser; // IWYU pragma: keep
+
+class cmMakefile;
+
namespace ArgumentParser {
-using StringList = std::vector<std::string>;
-using MultiStringList = std::vector<StringList>;
+class ParseResult
+{
+ std::map<cm::string_view, std::string> KeywordErrors;
+
+public:
+ explicit operator bool() const { return this->KeywordErrors.empty(); }
+
+ void AddKeywordError(cm::string_view key, cm::string_view text)
+
+ {
+ this->KeywordErrors[key] += text;
+ }
+
+ std::map<cm::string_view, std::string> const& GetKeywordErrors() const
+ {
+ return this->KeywordErrors;
+ }
+
+ bool MaybeReportError(cmMakefile& mf) const;
+};
+
+template <typename Result>
+typename std::enable_if<std::is_base_of<ParseResult, Result>::value,
+ ParseResult*>::type
+AsParseResultPtr(Result& result)
+{
+ return &result;
+}
+
+template <typename Result>
+typename std::enable_if<!std::is_base_of<ParseResult, Result>::value,
+ ParseResult*>::type
+AsParseResultPtr(Result&)
+{
+ return nullptr;
+}
+
+enum class Continue
+{
+ No,
+ Yes,
+};
+
+struct ExpectAtLeast
+{
+ std::size_t Count = 0;
+
+ ExpectAtLeast(std::size_t count)
+ : Count(count)
+ {
+ }
+};
class Instance;
-using Action = std::function<void(Instance&, void*)>;
+using KeywordAction = std::function<void(Instance&)>;
+using KeywordNameAction = std::function<void(Instance&, cm::string_view)>;
+using PositionAction =
+ std::function<void(Instance&, std::size_t, cm::string_view)>;
-// using ActionMap = cm::flat_map<cm::string_view, Action>;
-class ActionMap : public std::vector<std::pair<cm::string_view, Action>>
+// using KeywordActionMap = cm::flat_map<cm::string_view, KeywordAction>;
+class KeywordActionMap
+ : public std::vector<std::pair<cm::string_view, KeywordAction>>
{
public:
- std::pair<iterator, bool> Emplace(cm::string_view name, Action action);
+ std::pair<iterator, bool> Emplace(cm::string_view name,
+ KeywordAction action);
const_iterator Find(cm::string_view name) const;
};
+// using PositionActionMap = cm::flat_map<cm::string_view, PositionAction>;
+class PositionActionMap
+ : public std::vector<std::pair<std::size_t, PositionAction>>
+{
+public:
+ std::pair<iterator, bool> Emplace(std::size_t pos, PositionAction action);
+ const_iterator Find(std::size_t pos) const;
+};
+
+class ActionMap
+{
+public:
+ KeywordActionMap Keywords;
+ KeywordNameAction KeywordMissingValue;
+ KeywordNameAction ParsedKeyword;
+ PositionActionMap Positions;
+};
+
+class Base
+{
+public:
+ using ExpectAtLeast = ArgumentParser::ExpectAtLeast;
+ using Continue = ArgumentParser::Continue;
+ using Instance = ArgumentParser::Instance;
+ using ParseResult = ArgumentParser::ParseResult;
+
+ ArgumentParser::ActionMap Bindings;
+
+ bool MaybeBind(cm::string_view name, KeywordAction action)
+ {
+ return this->Bindings.Keywords.Emplace(name, std::move(action)).second;
+ }
+
+ void Bind(cm::string_view name, KeywordAction action)
+ {
+ bool const inserted = this->MaybeBind(name, std::move(action));
+ assert(inserted);
+ static_cast<void>(inserted);
+ }
+
+ void BindParsedKeyword(KeywordNameAction action)
+ {
+ assert(!this->Bindings.ParsedKeyword);
+ this->Bindings.ParsedKeyword = std::move(action);
+ }
+
+ void BindKeywordMissingValue(KeywordNameAction action)
+ {
+ assert(!this->Bindings.KeywordMissingValue);
+ this->Bindings.KeywordMissingValue = std::move(action);
+ }
+
+ void Bind(std::size_t pos, PositionAction action)
+ {
+ bool const inserted =
+ this->Bindings.Positions.Emplace(pos, std::move(action)).second;
+ assert(inserted);
+ static_cast<void>(inserted);
+ }
+};
+
class Instance
{
public:
- Instance(ActionMap const& bindings)
+ Instance(ActionMap const& bindings, ParseResult* parseResult,
+ std::vector<std::string>* unparsedArguments, void* result = nullptr)
: Bindings(bindings)
+ , ParseResults(parseResult)
+ , UnparsedArguments(unparsedArguments)
+ , Result(result)
{
}
+ void Bind(std::function<Continue(cm::string_view)> f, ExpectAtLeast expect);
void Bind(bool& val);
void Bind(std::string& val);
- void Bind(StringList& val);
- void Bind(MultiStringList& val);
+ void Bind(NonEmpty<std::string>& val);
+ void Bind(Maybe<std::string>& val);
+ void Bind(MaybeEmpty<std::vector<std::string>>& val);
+ void Bind(NonEmpty<std::vector<std::string>>& val);
+ void Bind(std::vector<std::vector<std::string>>& val);
+
+ // cm::optional<> records the presence the keyword to which it binds.
+ template <typename T>
+ void Bind(cm::optional<T>& optVal)
+ {
+ if (!optVal) {
+ optVal.emplace();
+ }
+ this->Bind(*optVal);
+ }
- void Consume(cm::string_view arg, void* result,
- std::vector<std::string>* unparsedArguments,
- std::vector<std::string>* keywordsMissingValue,
- std::vector<std::string>* parsedKeywords);
+ template <typename Range>
+ void Parse(Range const& args, std::size_t pos = 0)
+ {
+ for (cm::string_view arg : args) {
+ this->Consume(pos++, arg);
+ }
+ this->FinishKeyword();
+ }
private:
ActionMap const& Bindings;
- std::string* CurrentString = nullptr;
- StringList* CurrentList = nullptr;
- bool ExpectValue = false;
+ ParseResult* ParseResults = nullptr;
+ std::vector<std::string>* UnparsedArguments = nullptr;
+ void* Result = nullptr;
+
+ cm::string_view Keyword;
+ std::size_t KeywordValuesSeen = 0;
+ std::size_t KeywordValuesExpected = 0;
+ std::function<Continue(cm::string_view)> KeywordValueFunc;
+ bool DoneWithPositional = false;
+
+ void Consume(std::size_t pos, cm::string_view arg);
+ void FinishKeyword();
+
+ template <typename Result>
+ friend class ::cmArgumentParser;
};
} // namespace ArgumentParser
template <typename Result>
-class cmArgumentParser
+class cmArgumentParser : private ArgumentParser::Base
{
public:
// I *think* this function could be made `constexpr` when the code is
@@ -65,83 +226,194 @@ public:
template <typename T>
cmArgumentParser& Bind(cm::static_string_view name, T Result::*member)
{
- bool const inserted =
- this->Bindings
- .Emplace(name,
- [member](ArgumentParser::Instance& instance, void* result) {
- instance.Bind(static_cast<Result*>(result)->*member);
- })
- .second;
- assert(inserted), (void)inserted;
+ this->Base::Bind(name, [member](Instance& instance) {
+ instance.Bind(static_cast<Result*>(instance.Result)->*member);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(cm::static_string_view name,
+ Continue (Result::*member)(cm::string_view),
+ ExpectAtLeast expect = { 1 })
+ {
+ this->Base::Bind(name, [member, expect](Instance& instance) {
+ Result* result = static_cast<Result*>(instance.Result);
+ instance.Bind(
+ [result, member](cm::string_view arg) -> Continue {
+ return (result->*member)(arg);
+ },
+ expect);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(cm::static_string_view name,
+ Continue (Result::*member)(cm::string_view,
+ cm::string_view),
+ ExpectAtLeast expect = { 1 })
+ {
+ this->Base::Bind(name, [member, expect](Instance& instance) {
+ Result* result = static_cast<Result*>(instance.Result);
+ cm::string_view keyword = instance.Keyword;
+ instance.Bind(
+ [result, member, keyword](cm::string_view arg) -> Continue {
+ return (result->*member)(keyword, arg);
+ },
+ expect);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(cm::static_string_view name,
+ std::function<Continue(Result&, cm::string_view)> f,
+ ExpectAtLeast expect = { 1 })
+ {
+ this->Base::Bind(name, [f, expect](Instance& instance) {
+ Result* result = static_cast<Result*>(instance.Result);
+ instance.Bind(
+ [result, &f](cm::string_view arg) -> Continue {
+ return f(*result, arg);
+ },
+ expect);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(
+ cm::static_string_view name,
+ std::function<Continue(Result&, cm::string_view, cm::string_view)> f,
+ ExpectAtLeast expect = { 1 })
+ {
+ this->Base::Bind(name, [f, expect](Instance& instance) {
+ Result* result = static_cast<Result*>(instance.Result);
+ cm::string_view keyword = instance.Keyword;
+ instance.Bind(
+ [result, keyword, &f](cm::string_view arg) -> Continue {
+ return f(*result, keyword, arg);
+ },
+ expect);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(std::size_t position,
+ cm::optional<std::string> Result::*member)
+ {
+ this->Base::Bind(
+ position,
+ [member](Instance& instance, std::size_t, cm::string_view arg) {
+ Result* result = static_cast<Result*>(instance.Result);
+ result->*member = arg;
+ });
+ return *this;
+ }
+
+ cmArgumentParser& BindParsedKeywords(
+ std::vector<cm::string_view> Result::*member)
+ {
+ this->Base::BindParsedKeyword(
+ [member](Instance& instance, cm::string_view arg) {
+ (static_cast<Result*>(instance.Result)->*member).emplace_back(arg);
+ });
return *this;
}
template <typename Range>
- void Parse(Result& result, Range const& args,
- std::vector<std::string>* unparsedArguments = nullptr,
- std::vector<std::string>* keywordsMissingValue = nullptr,
- std::vector<std::string>* parsedKeywords = nullptr) const
+ bool Parse(Result& result, Range const& args,
+ std::vector<std::string>* unparsedArguments,
+ std::size_t pos = 0) const
{
- ArgumentParser::Instance instance(this->Bindings);
- for (cm::string_view arg : args) {
- instance.Consume(arg, &result, unparsedArguments, keywordsMissingValue,
- parsedKeywords);
- }
+ using ArgumentParser::AsParseResultPtr;
+ ParseResult* parseResultPtr = AsParseResultPtr(result);
+ Instance instance(this->Bindings, parseResultPtr, unparsedArguments,
+ &result);
+ instance.Parse(args, pos);
+ return parseResultPtr ? static_cast<bool>(*parseResultPtr) : true;
}
template <typename Range>
- Result Parse(Range const& args,
- std::vector<std::string>* unparsedArguments = nullptr,
- std::vector<std::string>* keywordsMissingValue = nullptr,
- std::vector<std::string>* parsedKeywords = nullptr) const
+ Result Parse(Range const& args, std::vector<std::string>* unparsedArguments,
+ std::size_t pos = 0) const
{
Result result;
- this->Parse(result, args, unparsedArguments, keywordsMissingValue,
- parsedKeywords);
+ this->Parse(result, args, unparsedArguments, pos);
return result;
}
-
-private:
- ArgumentParser::ActionMap Bindings;
};
template <>
-class cmArgumentParser<void>
+class cmArgumentParser<void> : private ArgumentParser::Base
{
public:
template <typename T>
cmArgumentParser& Bind(cm::static_string_view name, T& ref)
{
- bool const inserted = this->Bind(cm::string_view(name), ref);
- assert(inserted), (void)inserted;
+ this->Base::Bind(name, [&ref](Instance& instance) { instance.Bind(ref); });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(cm::static_string_view name,
+ std::function<Continue(cm::string_view)> f,
+ ExpectAtLeast expect = { 1 })
+ {
+ this->Base::Bind(name, [f, expect](Instance& instance) {
+ instance.Bind([&f](cm::string_view arg) -> Continue { return f(arg); },
+ expect);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(
+ cm::static_string_view name,
+ std::function<Continue(cm::string_view, cm::string_view)> f,
+ ExpectAtLeast expect = { 1 })
+ {
+ this->Base::Bind(name, [f, expect](Instance& instance) {
+ cm::string_view keyword = instance.Keyword;
+ instance.Bind(
+ [keyword, &f](cm::string_view arg) -> Continue {
+ return f(keyword, arg);
+ },
+ expect);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& Bind(std::size_t position, cm::optional<std::string>& ref)
+ {
+ this->Base::Bind(position,
+ [&ref](Instance&, std::size_t, cm::string_view arg) {
+ ref = std::string(arg);
+ });
+ return *this;
+ }
+
+ cmArgumentParser& BindParsedKeywords(std::vector<cm::string_view>& ref)
+ {
+ this->Base::BindParsedKeyword(
+ [&ref](Instance&, cm::string_view arg) { ref.emplace_back(arg); });
return *this;
}
template <typename Range>
- void Parse(Range const& args,
- std::vector<std::string>* unparsedArguments = nullptr,
- std::vector<std::string>* keywordsMissingValue = nullptr,
- std::vector<std::string>* parsedKeywords = nullptr) const
+ ParseResult Parse(Range const& args,
+ std::vector<std::string>* unparsedArguments,
+ std::size_t pos = 0) const
{
- ArgumentParser::Instance instance(this->Bindings);
- for (cm::string_view arg : args) {
- instance.Consume(arg, nullptr, unparsedArguments, keywordsMissingValue,
- parsedKeywords);
- }
+ ParseResult parseResult;
+ Instance instance(this->Bindings, &parseResult, unparsedArguments);
+ instance.Parse(args, pos);
+ return parseResult;
}
protected:
+ using Base::Instance;
+ using Base::BindKeywordMissingValue;
+
template <typename T>
bool Bind(cm::string_view name, T& ref)
{
- return this->Bindings
- .Emplace(name,
- [&ref](ArgumentParser::Instance& instance, void*) {
- instance.Bind(ref);
- })
- .second;
+ return this->MaybeBind(name,
+ [&ref](Instance& instance) { instance.Bind(ref); });
}
-
-private:
- ArgumentParser::ActionMap Bindings;
};
diff --git a/Source/cmArgumentParserTypes.h b/Source/cmArgumentParserTypes.h
new file mode 100644
index 0000000..7daae09
--- /dev/null
+++ b/Source/cmArgumentParserTypes.h
@@ -0,0 +1,69 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#if defined(__SUNPRO_CC)
+
+# include <string>
+# include <vector>
+
+namespace ArgumentParser {
+
+template <typename T>
+struct Maybe;
+template <>
+struct Maybe<std::string> : public std::string
+{
+ using std::string::basic_string;
+};
+
+template <typename T>
+struct MaybeEmpty;
+template <typename T>
+struct MaybeEmpty<std::vector<T>> : public std::vector<T>
+{
+ using std::vector<T>::vector;
+};
+
+template <typename T>
+struct NonEmpty;
+template <typename T>
+struct NonEmpty<std::vector<T>> : public std::vector<T>
+{
+ using std::vector<T>::vector;
+};
+template <>
+struct NonEmpty<std::string> : public std::string
+{
+ using std::string::basic_string;
+};
+
+} // namespace ArgumentParser
+
+#else
+
+namespace ArgumentParser {
+
+template <typename T>
+struct Maybe : public T
+{
+ using T::T;
+};
+
+template <typename T>
+struct MaybeEmpty : public T
+{
+ using T::T;
+};
+
+template <typename T>
+struct NonEmpty : public T
+{
+ using T::T;
+};
+
+} // namespace ArgumentParser
+
+#endif
diff --git a/Source/cmBlockCommand.cxx b/Source/cmBlockCommand.cxx
new file mode 100644
index 0000000..ec79149
--- /dev/null
+++ b/Source/cmBlockCommand.cxx
@@ -0,0 +1,197 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmBlockCommand.h"
+
+#include <cstdint> // IWYU pragma: keep
+#include <utility>
+
+#include <cm/memory>
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/enum_set>
+#include <cmext/string_view>
+
+#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
+#include "cmExecutionStatus.h"
+#include "cmFunctionBlocker.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+enum class ScopeType : std::uint8_t
+{
+ VARIABLES,
+ POLICIES
+};
+using ScopeSet = cm::enum_set<ScopeType>;
+
+class BlockScopePushPop
+{
+public:
+ BlockScopePushPop(cmMakefile* m, const ScopeSet& scopes);
+ ~BlockScopePushPop() = default;
+
+ BlockScopePushPop(const BlockScopePushPop&) = delete;
+ BlockScopePushPop& operator=(const BlockScopePushPop&) = delete;
+
+private:
+ std::unique_ptr<cmMakefile::PolicyPushPop> PolicyScope;
+ std::unique_ptr<cmMakefile::VariablePushPop> VariableScope;
+};
+
+BlockScopePushPop::BlockScopePushPop(cmMakefile* mf, const ScopeSet& scopes)
+{
+ if (scopes.contains(ScopeType::POLICIES)) {
+ this->PolicyScope = cm::make_unique<cmMakefile::PolicyPushPop>(mf);
+ }
+ if (scopes.contains(ScopeType::VARIABLES)) {
+ this->VariableScope = cm::make_unique<cmMakefile::VariablePushPop>(mf);
+ }
+}
+
+class cmBlockFunctionBlocker : public cmFunctionBlocker
+{
+public:
+ cmBlockFunctionBlocker(cmMakefile* mf, const ScopeSet& scopes,
+ std::vector<std::string> variableNames);
+ ~cmBlockFunctionBlocker() override;
+
+ cm::string_view StartCommandName() const override { return "block"_s; }
+ cm::string_view EndCommandName() const override { return "endblock"_s; }
+
+ bool EndCommandSupportsArguments() const override { return false; }
+
+ bool ArgumentsMatch(cmListFileFunction const& lff,
+ cmMakefile& mf) const override;
+
+ bool Replay(std::vector<cmListFileFunction> functions,
+ cmExecutionStatus& inStatus) override;
+
+private:
+ cmMakefile* Makefile;
+ ScopeSet Scopes;
+ BlockScopePushPop BlockScope;
+ std::vector<std::string> VariableNames;
+};
+
+cmBlockFunctionBlocker::cmBlockFunctionBlocker(
+ cmMakefile* const mf, const ScopeSet& scopes,
+ std::vector<std::string> variableNames)
+ : Makefile{ mf }
+ , Scopes{ scopes }
+ , BlockScope{ mf, scopes }
+ , VariableNames{ std::move(variableNames) }
+{
+}
+
+cmBlockFunctionBlocker::~cmBlockFunctionBlocker()
+{
+ if (this->Scopes.contains(ScopeType::VARIABLES)) {
+ this->Makefile->RaiseScope(this->VariableNames);
+ }
+}
+
+bool cmBlockFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
+ cmMakefile&) const
+{
+ // no arguments expected for endblock()
+ // but this method should not be called because EndCommandHasArguments()
+ // returns false.
+ return lff.Arguments().empty();
+}
+
+bool cmBlockFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
+ cmExecutionStatus& inStatus)
+{
+ auto& mf = inStatus.GetMakefile();
+
+ // Invoke all the functions that were collected in the block.
+ for (cmListFileFunction const& fn : functions) {
+ cmExecutionStatus status(mf);
+ mf.ExecuteCommand(fn, status);
+ if (status.GetReturnInvoked()) {
+ mf.RaiseScope(status.GetReturnVariables());
+ inStatus.SetReturnInvoked(status.GetReturnVariables());
+ return true;
+ }
+ if (status.GetBreakInvoked()) {
+ inStatus.SetBreakInvoked();
+ return true;
+ }
+ if (status.GetContinueInvoked()) {
+ inStatus.SetContinueInvoked();
+ return true;
+ }
+ if (cmSystemTools::GetFatalErrorOccurred()) {
+ return true;
+ }
+ }
+ return true;
+}
+
+} // anonymous namespace
+
+bool cmBlockCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ struct Arguments : public ArgumentParser::ParseResult
+ {
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> ScopeFor;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Propagate;
+ };
+ static auto const parser = cmArgumentParser<Arguments>{}
+ .Bind("SCOPE_FOR"_s, &Arguments::ScopeFor)
+ .Bind("PROPAGATE"_s, &Arguments::Propagate);
+ std::vector<std::string> unrecognizedArguments;
+ auto parsedArgs = parser.Parse(args, &unrecognizedArguments);
+
+ if (!unrecognizedArguments.empty()) {
+ status.SetError(cmStrCat("called with unsupported argument \"",
+ unrecognizedArguments[0], '"'));
+ cmSystemTools::SetFatalErrorOccurred();
+ return false;
+ }
+
+ if (parsedArgs.MaybeReportError(status.GetMakefile())) {
+ cmSystemTools::SetFatalErrorOccurred();
+ return true;
+ }
+
+ ScopeSet scopes;
+
+ if (parsedArgs.ScopeFor) {
+ for (auto const& scope : *parsedArgs.ScopeFor) {
+ if (scope == "VARIABLES"_s) {
+ scopes.insert(ScopeType::VARIABLES);
+ continue;
+ }
+ if (scope == "POLICIES"_s) {
+ scopes.insert(ScopeType::POLICIES);
+ continue;
+ }
+ status.SetError(cmStrCat("SCOPE_FOR unsupported scope \"", scope, '"'));
+ cmSystemTools::SetFatalErrorOccurred();
+ return false;
+ }
+ } else {
+ scopes = { ScopeType::VARIABLES, ScopeType::POLICIES };
+ }
+ if (!scopes.contains(ScopeType::VARIABLES) &&
+ !parsedArgs.Propagate.empty()) {
+ status.SetError(
+ "PROPAGATE cannot be specified without a new scope for VARIABLES");
+ cmSystemTools::SetFatalErrorOccurred();
+ return false;
+ }
+
+ // create a function blocker
+ auto fb = cm::make_unique<cmBlockFunctionBlocker>(
+ &status.GetMakefile(), scopes, parsedArgs.Propagate);
+ status.GetMakefile().AddFunctionBlocker(std::move(fb));
+
+ return true;
+}
diff --git a/Source/cmBlockCommand.h b/Source/cmBlockCommand.h
new file mode 100644
index 0000000..5fd8f42
--- /dev/null
+++ b/Source/cmBlockCommand.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+class cmExecutionStatus;
+
+/// Starts block() ... endblock() block
+bool cmBlockCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx
index 0750eea..58129a0 100644
--- a/Source/cmCMakeHostSystemInformationCommand.cxx
+++ b/Source/cmCMakeHostSystemInformationCommand.cxx
@@ -474,7 +474,7 @@ bool QueryWindowsRegistry(Range args, cmExecutionStatus& status,
}
std::string const& key = *args.begin();
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
std::string ValueName;
bool ValueNames = false;
@@ -491,19 +491,15 @@ bool QueryWindowsRegistry(Range args, cmExecutionStatus& status,
.Bind("SEPARATOR"_s, &Arguments::Separator)
.Bind("ERROR_VARIABLE"_s, &Arguments::ErrorVariable);
std::vector<std::string> invalidArgs;
- std::vector<std::string> keywordsMissingValue;
- Arguments const arguments =
- parser.Parse(args.advance(1), &invalidArgs, &keywordsMissingValue);
+ Arguments const arguments = parser.Parse(args.advance(1), &invalidArgs);
if (!invalidArgs.empty()) {
status.SetError(cmStrCat("given invalid argument(s) \"",
cmJoin(invalidArgs, ", "_s), "\"."));
return false;
}
- if (!keywordsMissingValue.empty()) {
- status.SetError(cmStrCat("missing expected value for argument(s) \"",
- cmJoin(keywordsMissingValue, ", "_s), "\"."));
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if ((!arguments.ValueName.empty() &&
(arguments.ValueNames || arguments.SubKeys)) ||
diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx
index a2aaa2a..68e658c 100644
--- a/Source/cmCMakeLanguageCommand.cxx
+++ b/Source/cmCMakeLanguageCommand.cxx
@@ -14,15 +14,18 @@
#include <cmext/string_view>
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmDependencyProvider.h"
#include "cmExecutionStatus.h"
#include "cmGlobalGenerator.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
+#include "cmMessageType.h"
#include "cmRange.h"
#include "cmState.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
+#include "cmake.h"
namespace {
@@ -33,13 +36,14 @@ bool FatalError(cmExecutionStatus& status, std::string const& error)
return false;
}
-std::array<cm::static_string_view, 12> InvalidCommands{
+std::array<cm::static_string_view, 14> InvalidCommands{
{ // clang-format off
"function"_s, "endfunction"_s,
"macro"_s, "endmacro"_s,
"if"_s, "elseif"_s, "else"_s, "endif"_s,
"while"_s, "endwhile"_s,
- "foreach"_s, "endforeach"_s
+ "foreach"_s, "endforeach"_s,
+ "block"_s, "endblock"_s
} // clang-format on
};
@@ -235,7 +239,7 @@ bool cmCMakeLanguageCommandSET_DEPENDENCY_PROVIDER(
struct SetProviderArgs
{
std::string Command;
- std::vector<std::string> Methods;
+ ArgumentParser::NonEmpty<std::vector<std::string>> Methods;
};
auto const ArgsParser =
@@ -303,6 +307,27 @@ bool cmCMakeLanguageCommandSET_DEPENDENCY_PROVIDER(
return true;
}
+
+bool cmCMakeLanguageCommandGET_MESSAGE_LOG_LEVEL(
+ std::vector<cmListFileArgument> const& args, cmExecutionStatus& status)
+{
+ cmMakefile& makefile = status.GetMakefile();
+ std::vector<std::string> expandedArgs;
+ makefile.ExpandArguments(args, expandedArgs);
+
+ if (args.size() < 2 || expandedArgs.size() > 2) {
+ return FatalError(
+ status,
+ "sub-command GET_MESSAGE_LOG_LEVEL expects exactly one argument");
+ }
+
+ Message::LogLevel logLevel = makefile.GetCurrentLogLevel();
+ std::string outputValue = cmake::LogLevelToString(logLevel);
+
+ const std::string& outputVariable = expandedArgs[1];
+ makefile.AddDefinition(outputVariable, outputValue);
+ return true;
+}
}
bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
@@ -451,5 +476,9 @@ bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
return cmCMakeLanguageCommandEVAL(args, status);
}
+ if (expArgs[expArg] == "GET_MESSAGE_LOG_LEVEL") {
+ return cmCMakeLanguageCommandGET_MESSAGE_LOG_LEVEL(args, status);
+ }
+
return FatalError(status, "called with unknown meta-operation");
}
diff --git a/Source/cmCMakePathCommand.cxx b/Source/cmCMakePathCommand.cxx
index bf94c2d..7755082 100644
--- a/Source/cmCMakePathCommand.cxx
+++ b/Source/cmCMakePathCommand.cxx
@@ -2,7 +2,6 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCMakePathCommand.h"
-#include <algorithm>
#include <functional>
#include <iomanip>
#include <map>
@@ -11,10 +10,12 @@
#include <utility>
#include <vector>
+#include <cm/optional>
#include <cm/string_view>
#include <cmext/string_view>
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmCMakePath.h"
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
@@ -43,15 +44,12 @@ public:
}
template <int Advance = 2>
- Result Parse(std::vector<std::string> const& args,
- std::vector<std::string>* keywordsMissingValue = nullptr,
- std::vector<std::string>* parsedKeywords = nullptr) const
+ Result Parse(std::vector<std::string> const& args) const
{
this->Inputs.clear();
return this->cmArgumentParser<Result>::Parse(
- cmMakeRange(args).advance(Advance), &this->Inputs, keywordsMissingValue,
- parsedKeywords);
+ cmMakeRange(args).advance(Advance), &this->Inputs);
}
const std::vector<std::string>& GetInputs() const { return this->Inputs; }
@@ -82,52 +80,14 @@ public:
template <int Advance = 2>
Result Parse(std::vector<std::string> const& args) const
{
- this->KeywordsMissingValue.clear();
- this->ParsedKeywords.clear();
-
return this->CMakePathArgumentParser<Result>::template Parse<Advance>(
- args, &this->KeywordsMissingValue, &this->ParsedKeywords);
- }
-
- const std::vector<std::string>& GetKeywordsMissingValue() const
- {
- return this->KeywordsMissingValue;
- }
- const std::vector<std::string>& GetParsedKeywords() const
- {
- return this->ParsedKeywords;
- }
-
- bool checkOutputVariable(const Result& arguments,
- cmExecutionStatus& status) const
- {
- if (std::find(this->GetKeywordsMissingValue().begin(),
- this->GetKeywordsMissingValue().end(),
- "OUTPUT_VARIABLE"_s) !=
- this->GetKeywordsMissingValue().end()) {
- status.SetError("OUTPUT_VARIABLE requires an argument.");
- return false;
- }
-
- if (std::find(this->GetParsedKeywords().begin(),
- this->GetParsedKeywords().end(),
- "OUTPUT_VARIABLE"_s) != this->GetParsedKeywords().end() &&
- arguments.Output.empty()) {
- status.SetError("Invalid name for output variable.");
- return false;
- }
-
- return true;
+ args);
}
-
-private:
- mutable std::vector<std::string> KeywordsMissingValue;
- mutable std::vector<std::string> ParsedKeywords;
};
-struct OutputVariable
+struct OutputVariable : public ArgumentParser::ParseResult
{
- std::string Output;
+ cm::optional<ArgumentParser::NonEmpty<std::string>> Output;
};
// Usable when OUTPUT_VARIABLE is the only option
class OutputVariableParser
@@ -297,8 +257,8 @@ bool HandleAppendCommand(std::vector<std::string> const& args,
const auto arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
cmCMakePath path(status.GetMakefile().GetSafeDefinition(args[1]));
@@ -307,7 +267,7 @@ bool HandleAppendCommand(std::vector<std::string> const& args,
}
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
@@ -319,8 +279,8 @@ bool HandleAppendStringCommand(std::vector<std::string> const& args,
const auto arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
std::string inputPath;
@@ -334,7 +294,7 @@ bool HandleAppendStringCommand(std::vector<std::string> const& args,
}
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
@@ -346,8 +306,8 @@ bool HandleRemoveFilenameCommand(std::vector<std::string> const& args,
const auto arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (!parser.GetInputs().empty()) {
@@ -364,7 +324,7 @@ bool HandleRemoveFilenameCommand(std::vector<std::string> const& args,
path.RemoveFileName();
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
@@ -376,8 +336,8 @@ bool HandleReplaceFilenameCommand(std::vector<std::string> const& args,
const auto arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (parser.GetInputs().size() > 1) {
@@ -395,7 +355,7 @@ bool HandleReplaceFilenameCommand(std::vector<std::string> const& args,
parser.GetInputs().empty() ? "" : parser.GetInputs().front());
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
@@ -403,9 +363,9 @@ bool HandleReplaceFilenameCommand(std::vector<std::string> const& args,
bool HandleRemoveExtensionCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
- std::string Output;
+ cm::optional<ArgumentParser::NonEmpty<std::string>> Output;
bool LastOnly = false;
};
@@ -415,8 +375,8 @@ bool HandleRemoveExtensionCommand(std::vector<std::string> const& args,
Arguments const arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (!parser.GetInputs().empty()) {
@@ -438,7 +398,7 @@ bool HandleRemoveExtensionCommand(std::vector<std::string> const& args,
}
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
@@ -446,9 +406,9 @@ bool HandleRemoveExtensionCommand(std::vector<std::string> const& args,
bool HandleReplaceExtensionCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
- std::string Output;
+ cm::optional<ArgumentParser::NonEmpty<std::string>> Output;
bool LastOnly = false;
};
@@ -458,8 +418,8 @@ bool HandleReplaceExtensionCommand(std::vector<std::string> const& args,
Arguments const arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (parser.GetInputs().size() > 1) {
@@ -483,7 +443,7 @@ bool HandleReplaceExtensionCommand(std::vector<std::string> const& args,
}
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
@@ -495,8 +455,8 @@ bool HandleNormalPathCommand(std::vector<std::string> const& args,
const auto arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (!parser.GetInputs().empty()) {
@@ -512,7 +472,7 @@ bool HandleNormalPathCommand(std::vector<std::string> const& args,
auto path = cmCMakePath(inputPath).Normal();
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
@@ -523,10 +483,10 @@ bool HandleTransformPathCommand(
const std::string& base)>& transform,
bool normalizeOption = false)
{
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
- std::string Output;
- std::string BaseDirectory;
+ cm::optional<ArgumentParser::NonEmpty<std::string>> Output;
+ cm::optional<std::string> BaseDirectory;
bool Normalize = false;
};
@@ -538,8 +498,8 @@ bool HandleTransformPathCommand(
Arguments arguments = parser.Parse(args);
- if (!parser.checkOutputVariable(arguments, status)) {
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (!parser.GetInputs().empty()) {
@@ -547,17 +507,11 @@ bool HandleTransformPathCommand(
return false;
}
- if (std::find(parser.GetKeywordsMissingValue().begin(),
- parser.GetKeywordsMissingValue().end(), "BASE_DIRECTORY"_s) !=
- parser.GetKeywordsMissingValue().end()) {
- status.SetError("BASE_DIRECTORY requires an argument.");
- return false;
- }
-
- if (std::find(parser.GetParsedKeywords().begin(),
- parser.GetParsedKeywords().end(),
- "BASE_DIRECTORY"_s) == parser.GetParsedKeywords().end()) {
- arguments.BaseDirectory = status.GetMakefile().GetCurrentSourceDirectory();
+ std::string baseDirectory;
+ if (arguments.BaseDirectory) {
+ baseDirectory = *arguments.BaseDirectory;
+ } else {
+ baseDirectory = status.GetMakefile().GetCurrentSourceDirectory();
}
std::string inputPath;
@@ -565,13 +519,13 @@ bool HandleTransformPathCommand(
return false;
}
- auto path = transform(cmCMakePath(inputPath), arguments.BaseDirectory);
+ auto path = transform(cmCMakePath(inputPath), baseDirectory);
if (arguments.Normalize) {
path = path.Normal();
}
status.GetMakefile().AddDefinition(
- arguments.Output.empty() ? args[1] : arguments.Output, path.String());
+ arguments.Output ? *arguments.Output : args[1], path.String());
return true;
}
diff --git a/Source/cmCMakePresetsGraph.cxx b/Source/cmCMakePresetsGraph.cxx
index b737c1f..7fbcdab 100644
--- a/Source/cmCMakePresetsGraph.cxx
+++ b/Source/cmCMakePresetsGraph.cxx
@@ -43,6 +43,7 @@ using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset;
using BuildPreset = cmCMakePresetsGraph::BuildPreset;
using TestPreset = cmCMakePresetsGraph::TestPreset;
+using PackagePreset = cmCMakePresetsGraph::PackagePreset;
using ExpandMacroResult = cmCMakePresetsGraphInternal::ExpandMacroResult;
using MacroExpander = cmCMakePresetsGraphInternal::MacroExpander;
@@ -301,6 +302,28 @@ bool ExpandMacros(const cmCMakePresetsGraph& graph, const TestPreset& preset,
return true;
}
+bool ExpandMacros(const cmCMakePresetsGraph& graph,
+ const PackagePreset& preset,
+ cm::optional<PackagePreset>& out,
+ const std::vector<MacroExpander>& macroExpanders)
+{
+ for (auto& variable : out->Variables) {
+ CHECK_EXPAND(out, variable.second, macroExpanders,
+ graph.GetVersion(preset));
+ }
+
+ CHECK_EXPAND(out, out->ConfigFile, macroExpanders, graph.GetVersion(preset));
+ CHECK_EXPAND(out, out->PackageName, macroExpanders,
+ graph.GetVersion(preset));
+ CHECK_EXPAND(out, out->PackageVersion, macroExpanders,
+ graph.GetVersion(preset));
+ CHECK_EXPAND(out, out->PackageDirectory, macroExpanders,
+ graph.GetVersion(preset));
+ CHECK_EXPAND(out, out->VendorName, macroExpanders, graph.GetVersion(preset));
+
+ return true;
+}
+
template <class T>
bool ExpandMacros(const cmCMakePresetsGraph& graph, const T& preset,
cm::optional<T>& out)
@@ -868,6 +891,44 @@ cmCMakePresetsGraph::TestPreset::VisitPresetAfterInherit(int /* version */)
return ReadFileResult::READ_OK;
}
+cmCMakePresetsGraph::ReadFileResult
+cmCMakePresetsGraph::PackagePreset::VisitPresetInherit(
+ const cmCMakePresetsGraph::Preset& parentPreset)
+{
+ auto& preset = *this;
+ const PackagePreset& parent =
+ static_cast<const PackagePreset&>(parentPreset);
+
+ InheritString(preset.ConfigurePreset, parent.ConfigurePreset);
+ InheritOptionalValue(preset.InheritConfigureEnvironment,
+ parent.InheritConfigureEnvironment);
+ InheritVector(preset.Generators, parent.Generators);
+ InheritVector(preset.Configurations, parent.Configurations);
+
+ for (auto const& v : parent.Variables) {
+ preset.Variables.insert(v);
+ }
+
+ InheritOptionalValue(preset.DebugOutput, parent.DebugOutput);
+ InheritOptionalValue(preset.VerboseOutput, parent.VerboseOutput);
+ InheritString(preset.PackageName, parent.PackageName);
+ InheritString(preset.PackageVersion, parent.PackageVersion);
+ InheritString(preset.PackageDirectory, parent.PackageDirectory);
+ InheritString(preset.VendorName, parent.VendorName);
+
+ return ReadFileResult::READ_OK;
+}
+
+cmCMakePresetsGraph::ReadFileResult
+cmCMakePresetsGraph::PackagePreset::VisitPresetAfterInherit(int /* version */)
+{
+ auto& preset = *this;
+ if (!preset.Hidden && preset.ConfigurePreset.empty()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+ return ReadFileResult::READ_OK;
+}
+
std::string cmCMakePresetsGraph::GetFilename(const std::string& sourceDir)
{
return cmStrCat(sourceDir, "/CMakePresets.json");
@@ -901,8 +962,9 @@ cmCMakePresetsGraph::ReadProjectPresetsInternal(bool allowNoFiles)
std::string filename = GetUserFilename(this->SourceDir);
std::vector<File*> inProgressFiles;
if (cmSystemTools::FileExists(filename)) {
- auto result = this->ReadJSONFile(filename, RootType::User,
- ReadReason::Root, inProgressFiles, file);
+ auto result =
+ this->ReadJSONFile(filename, RootType::User, ReadReason::Root,
+ inProgressFiles, file, this->errors);
if (result != ReadFileResult::READ_OK) {
return result;
}
@@ -910,8 +972,9 @@ cmCMakePresetsGraph::ReadProjectPresetsInternal(bool allowNoFiles)
} else {
filename = GetFilename(this->SourceDir);
if (cmSystemTools::FileExists(filename)) {
- auto result = this->ReadJSONFile(
- filename, RootType::Project, ReadReason::Root, inProgressFiles, file);
+ auto result =
+ this->ReadJSONFile(filename, RootType::Project, ReadReason::Root,
+ inProgressFiles, file, this->errors);
if (result != ReadFileResult::READ_OK) {
return result;
}
@@ -928,6 +991,7 @@ cmCMakePresetsGraph::ReadProjectPresetsInternal(bool allowNoFiles)
CHECK_OK(ComputePresetInheritance(this->ConfigurePresets, *this));
CHECK_OK(ComputePresetInheritance(this->BuildPresets, *this));
CHECK_OK(ComputePresetInheritance(this->TestPresets, *this));
+ CHECK_OK(ComputePresetInheritance(this->PackagePresets, *this));
for (auto& it : this->ConfigurePresets) {
if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
@@ -983,6 +1047,30 @@ cmCMakePresetsGraph::ReadProjectPresetsInternal(bool allowNoFiles)
}
}
+ for (auto& it : this->PackagePresets) {
+ if (!it.second.Unexpanded.Hidden) {
+ const auto configurePreset =
+ this->ConfigurePresets.find(it.second.Unexpanded.ConfigurePreset);
+ if (configurePreset == this->ConfigurePresets.end()) {
+ return ReadFileResult::INVALID_CONFIGURE_PRESET;
+ }
+ if (!it.second.Unexpanded.OriginFile->ReachableFiles.count(
+ configurePreset->second.Unexpanded.OriginFile)) {
+ return ReadFileResult::CONFIGURE_PRESET_UNREACHABLE_FROM_FILE;
+ }
+
+ if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true)) {
+ it.second.Unexpanded.Environment.insert(
+ configurePreset->second.Unexpanded.Environment.begin(),
+ configurePreset->second.Unexpanded.Environment.end());
+ }
+ }
+
+ if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
+ return ReadFileResult::INVALID_MACRO_EXPANSION;
+ }
+ }
+
return ReadFileResult::READ_OK;
}
@@ -1026,6 +1114,8 @@ const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result)
case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED:
return "File version must be 2 or higher for build and test preset "
"support.";
+ case ReadFileResult::PACKAGE_PRESETS_UNSUPPORTED:
+ return "File version must be 6 or higher for package preset support";
case ReadFileResult::INCLUDE_UNSUPPORTED:
return "File version must be 4 or higher for include support";
case ReadFileResult::INVALID_INCLUDE:
@@ -1057,14 +1147,26 @@ void cmCMakePresetsGraph::ClearPresets()
this->ConfigurePresets.clear();
this->BuildPresets.clear();
this->TestPresets.clear();
+ this->PackagePresets.clear();
this->ConfigurePresetOrder.clear();
this->BuildPresetOrder.clear();
this->TestPresetOrder.clear();
+ this->PackagePresetOrder.clear();
this->Files.clear();
}
+void cmCMakePresetsGraph::printPrecedingNewline(PrintPrecedingNewline* newline)
+{
+ if (newline) {
+ if (*newline == PrintPrecedingNewline::True) {
+ std::cout << std::endl;
+ }
+ *newline = PrintPrecedingNewline::True;
+ }
+}
+
void cmCMakePresetsGraph::PrintPresets(
const std::vector<const cmCMakePresetsGraph::Preset*>& presets)
{
@@ -1093,13 +1195,16 @@ void cmCMakePresetsGraph::PrintPresets(
}
}
-void cmCMakePresetsGraph::PrintConfigurePresetList() const
+void cmCMakePresetsGraph::PrintConfigurePresetList(
+ PrintPrecedingNewline* newline) const
{
- PrintConfigurePresetList([](const ConfigurePreset&) { return true; });
+ PrintConfigurePresetList([](const ConfigurePreset&) { return true; },
+ newline);
}
void cmCMakePresetsGraph::PrintConfigurePresetList(
- const std::function<bool(const ConfigurePreset&)>& filter) const
+ const std::function<bool(const ConfigurePreset&)>& filter,
+ PrintPrecedingNewline* newline) const
{
std::vector<const cmCMakePresetsGraph::Preset*> presets;
for (auto const& p : this->ConfigurePresetOrder) {
@@ -1112,12 +1217,14 @@ void cmCMakePresetsGraph::PrintConfigurePresetList(
}
if (!presets.empty()) {
+ printPrecedingNewline(newline);
std::cout << "Available configure presets:\n\n";
cmCMakePresetsGraph::PrintPresets(presets);
}
}
-void cmCMakePresetsGraph::PrintBuildPresetList() const
+void cmCMakePresetsGraph::PrintBuildPresetList(
+ PrintPrecedingNewline* newline) const
{
std::vector<const cmCMakePresetsGraph::Preset*> presets;
for (auto const& p : this->BuildPresetOrder) {
@@ -1130,12 +1237,14 @@ void cmCMakePresetsGraph::PrintBuildPresetList() const
}
if (!presets.empty()) {
+ printPrecedingNewline(newline);
std::cout << "Available build presets:\n\n";
cmCMakePresetsGraph::PrintPresets(presets);
}
}
-void cmCMakePresetsGraph::PrintTestPresetList() const
+void cmCMakePresetsGraph::PrintTestPresetList(
+ PrintPrecedingNewline* newline) const
{
std::vector<const cmCMakePresetsGraph::Preset*> presets;
for (auto const& p : this->TestPresetOrder) {
@@ -1148,16 +1257,45 @@ void cmCMakePresetsGraph::PrintTestPresetList() const
}
if (!presets.empty()) {
+ printPrecedingNewline(newline);
std::cout << "Available test presets:\n\n";
cmCMakePresetsGraph::PrintPresets(presets);
}
}
+void cmCMakePresetsGraph::PrintPackagePresetList(
+ PrintPrecedingNewline* newline) const
+{
+ this->PrintPackagePresetList([](const PackagePreset&) { return true; },
+ newline);
+}
+
+void cmCMakePresetsGraph::PrintPackagePresetList(
+ const std::function<bool(const PackagePreset&)>& filter,
+ PrintPrecedingNewline* newline) const
+{
+ std::vector<const cmCMakePresetsGraph::Preset*> presets;
+ for (auto const& p : this->PackagePresetOrder) {
+ auto const& preset = this->PackagePresets.at(p);
+ if (!preset.Unexpanded.Hidden && preset.Expanded &&
+ preset.Expanded->ConditionResult && filter(preset.Unexpanded)) {
+ presets.push_back(
+ static_cast<const cmCMakePresetsGraph::Preset*>(&preset.Unexpanded));
+ }
+ }
+
+ if (!presets.empty()) {
+ printPrecedingNewline(newline);
+ std::cout << "Available package presets:\n\n";
+ cmCMakePresetsGraph::PrintPresets(presets);
+ }
+}
+
void cmCMakePresetsGraph::PrintAllPresets() const
{
- this->PrintConfigurePresetList();
- std::cout << std::endl;
- this->PrintBuildPresetList();
- std::cout << std::endl;
- this->PrintTestPresetList();
+ PrintPrecedingNewline newline = PrintPrecedingNewline::False;
+ this->PrintConfigurePresetList(&newline);
+ this->PrintBuildPresetList(&newline);
+ this->PrintTestPresetList(&newline);
+ this->PrintPackagePresetList(&newline);
}
diff --git a/Source/cmCMakePresetsGraph.h b/Source/cmCMakePresetsGraph.h
index f1f8662..806a36d 100644
--- a/Source/cmCMakePresetsGraph.h
+++ b/Source/cmCMakePresetsGraph.h
@@ -41,6 +41,7 @@ public:
CONFIGURE_PRESET_UNREACHABLE_FROM_FILE,
INVALID_MACRO_EXPANSION,
BUILD_TEST_PRESETS_UNSUPPORTED,
+ PACKAGE_PRESETS_UNSUPPORTED,
INCLUDE_UNSUPPORTED,
INVALID_INCLUDE,
INVALID_CONFIGURE_PRESET,
@@ -52,6 +53,7 @@ public:
TEST_OUTPUT_TRUNCATION_UNSUPPORTED,
};
+ std::string errors;
enum class ArchToolsetStrategy
{
Set,
@@ -325,6 +327,42 @@ public:
ReadFileResult VisitPresetAfterInherit(int /* version */) override;
};
+ class PackagePreset : public Preset
+ {
+ public:
+ PackagePreset() = default;
+ PackagePreset(PackagePreset&& /*other*/) = default;
+ PackagePreset(const PackagePreset& /*other*/) = default;
+ PackagePreset& operator=(const PackagePreset& /*other*/) = default;
+ ~PackagePreset() override = default;
+#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
+ PackagePreset& operator=(PackagePreset&& /*other*/) = default;
+#else
+ // The move assignment operators for several STL classes did not become
+ // noexcept until C++17, which causes some tools to warn about this move
+ // assignment operator throwing an exception when it shouldn't.
+ PackagePreset& operator=(PackagePreset&& /*other*/) = delete;
+#endif
+
+ std::string ConfigurePreset;
+ cm::optional<bool> InheritConfigureEnvironment;
+ std::vector<std::string> Generators;
+ std::vector<std::string> Configurations;
+ std::map<std::string, std::string> Variables;
+ std::string ConfigFile;
+
+ cm::optional<bool> DebugOutput;
+ cm::optional<bool> VerboseOutput;
+
+ std::string PackageName;
+ std::string PackageVersion;
+ std::string PackageDirectory;
+ std::string VendorName;
+
+ ReadFileResult VisitPresetInherit(const Preset& parent) override;
+ ReadFileResult VisitPresetAfterInherit(int /* version */) override;
+ };
+
template <class T>
class PresetPair
{
@@ -336,10 +374,12 @@ public:
std::map<std::string, PresetPair<ConfigurePreset>> ConfigurePresets;
std::map<std::string, PresetPair<BuildPreset>> BuildPresets;
std::map<std::string, PresetPair<TestPreset>> TestPresets;
+ std::map<std::string, PresetPair<PackagePreset>> PackagePresets;
std::vector<std::string> ConfigurePresetOrder;
std::vector<std::string> BuildPresetOrder;
std::vector<std::string> TestPresetOrder;
+ std::vector<std::string> PackagePresetOrder;
std::string SourceDir;
std::vector<std::unique_ptr<File>> Files;
@@ -382,13 +422,26 @@ public:
return "";
}
+ enum class PrintPrecedingNewline
+ {
+ False,
+ True,
+ };
+ static void printPrecedingNewline(PrintPrecedingNewline* p);
+
static void PrintPresets(
const std::vector<const cmCMakePresetsGraph::Preset*>& presets);
- void PrintConfigurePresetList() const;
void PrintConfigurePresetList(
- const std::function<bool(const ConfigurePreset&)>& filter) const;
- void PrintBuildPresetList() const;
- void PrintTestPresetList() const;
+ PrintPrecedingNewline* newline = nullptr) const;
+ void PrintConfigurePresetList(
+ const std::function<bool(const ConfigurePreset&)>& filter,
+ PrintPrecedingNewline* newline = nullptr) const;
+ void PrintBuildPresetList(PrintPrecedingNewline* newline = nullptr) const;
+ void PrintTestPresetList(PrintPrecedingNewline* newline = nullptr) const;
+ void PrintPackagePresetList(PrintPrecedingNewline* newline = nullptr) const;
+ void PrintPackagePresetList(
+ const std::function<bool(const PackagePreset&)>& filter,
+ PrintPrecedingNewline* newline = nullptr) const;
void PrintAllPresets() const;
private:
@@ -407,7 +460,7 @@ private:
ReadFileResult ReadProjectPresetsInternal(bool allowNoFiles);
ReadFileResult ReadJSONFile(const std::string& filename, RootType rootType,
ReadReason readReason,
- std::vector<File*>& inProgressFiles,
- File*& file);
+ std::vector<File*>& inProgressFiles, File*& file,
+ std::string& errMsg);
void ClearPresets();
};
diff --git a/Source/cmCMakePresetsGraphInternal.h b/Source/cmCMakePresetsGraphInternal.h
index f7c7349..40af356 100644
--- a/Source/cmCMakePresetsGraphInternal.h
+++ b/Source/cmCMakePresetsGraphInternal.h
@@ -147,6 +147,10 @@ cmCMakePresetsGraph::ReadFileResult BuildPresetsHelper(
cmCMakePresetsGraph::ReadFileResult TestPresetsHelper(
std::vector<cmCMakePresetsGraph::TestPreset>& out, const Json::Value* value);
+cmCMakePresetsGraph::ReadFileResult PackagePresetsHelper(
+ std::vector<cmCMakePresetsGraph::PackagePreset>& out,
+ const Json::Value* value);
+
cmJSONHelper<std::nullptr_t, cmCMakePresetsGraph::ReadFileResult> VendorHelper(
cmCMakePresetsGraph::ReadFileResult error);
diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx
index d11e839..4fba7d9 100644
--- a/Source/cmCMakePresetsGraphReadJSON.cxx
+++ b/Source/cmCMakePresetsGraphReadJSON.cxx
@@ -34,7 +34,7 @@ using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy;
using JSONHelperBuilder = cmJSONHelperBuilder<ReadFileResult>;
constexpr int MIN_VERSION = 1;
-constexpr int MAX_VERSION = 5;
+constexpr int MAX_VERSION = 6;
struct CMakeVersion
{
@@ -49,6 +49,7 @@ struct RootPresets
std::vector<cmCMakePresetsGraph::ConfigurePreset> ConfigurePresets;
std::vector<cmCMakePresetsGraph::BuildPreset> BuildPresets;
std::vector<cmCMakePresetsGraph::TestPreset> TestPresets;
+ std::vector<cmCMakePresetsGraph::PackagePreset> PackagePresets;
std::vector<std::string> Include;
};
@@ -281,6 +282,8 @@ auto const RootPresetsHelper =
cmCMakePresetsGraphInternal::BuildPresetsHelper, false)
.Bind("testPresets"_s, &RootPresets::TestPresets,
cmCMakePresetsGraphInternal::TestPresetsHelper, false)
+ .Bind("packagePresets"_s, &RootPresets::PackagePresets,
+ cmCMakePresetsGraphInternal::PackagePresetsHelper, false)
.Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
CMakeVersionHelper, false)
.Bind("include"_s, &RootPresets::Include, IncludeVectorHelper, false)
@@ -411,7 +414,7 @@ cmCMakePresetsGraph::ReadFileResult EnvironmentMapHelper(
cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
const std::string& filename, RootType rootType, ReadReason readReason,
- std::vector<File*>& inProgressFiles, File*& file)
+ std::vector<File*>& inProgressFiles, File*& file, std::string& errMsg)
{
ReadFileResult result;
@@ -430,6 +433,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
cmsys::ifstream fin(filename.c_str());
if (!fin) {
+ errMsg = cmStrCat(filename, ": Failed to read file\n", errMsg);
return ReadFileResult::FILE_NOT_FOUND;
}
// If there's a BOM, toss it.
@@ -438,7 +442,8 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
Json::Value root;
Json::CharReaderBuilder builder;
Json::CharReaderBuilder::strictMode(&builder.settings_);
- if (!Json::parseFromStream(builder, fin, &root, nullptr)) {
+ if (!Json::parseFromStream(builder, fin, &root, &errMsg)) {
+ errMsg = cmStrCat(filename, ":\n", errMsg);
return ReadFileResult::JSON_PARSE_ERROR;
}
@@ -456,6 +461,11 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED;
}
+ // Support for package presets added in version 6.
+ if (v < 6 && root.isMember("packagePresets")) {
+ return ReadFileResult::PACKAGE_PRESETS_UNSUPPORTED;
+ }
+
// Support for include added in version 4.
if (v < 4 && root.isMember("include")) {
return ReadFileResult::INCLUDE_UNSUPPORTED;
@@ -490,6 +500,8 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
for (auto& preset : presets.ConfigurePresets) {
preset.OriginFile = file;
if (preset.Name.empty()) {
+ errMsg += R"(\n\t)";
+ errMsg += filename;
return ReadFileResult::INVALID_PRESET;
}
@@ -523,6 +535,8 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
for (auto& preset : presets.BuildPresets) {
preset.OriginFile = file;
if (preset.Name.empty()) {
+ errMsg += R"(\n\t)";
+ errMsg += filename;
return ReadFileResult::INVALID_PRESET;
}
@@ -567,14 +581,34 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
this->TestPresetOrder.push_back(preset.Name);
}
+ for (auto& preset : presets.PackagePresets) {
+ preset.OriginFile = file;
+ if (preset.Name.empty()) {
+ return ReadFileResult::INVALID_PRESET;
+ }
+
+ PresetPair<PackagePreset> presetPair;
+ presetPair.Unexpanded = preset;
+ presetPair.Expanded = cm::nullopt;
+ if (!this->PackagePresets.emplace(preset.Name, presetPair).second) {
+ return ReadFileResult::DUPLICATE_PRESETS;
+ }
+
+ // Support for conditions added in version 3, but this requires version 5
+ // already, so no action needed.
+
+ this->PackagePresetOrder.push_back(preset.Name);
+ }
+
auto const includeFile = [this, &inProgressFiles, file](
const std::string& include, RootType rootType2,
- ReadReason readReason2) -> ReadFileResult {
+ ReadReason readReason2,
+ std::string& FailureMessage) -> ReadFileResult {
ReadFileResult r;
File* includedFile;
if ((r = this->ReadJSONFile(include, rootType2, readReason2,
- inProgressFiles, includedFile)) !=
- ReadFileResult::READ_OK) {
+ inProgressFiles, includedFile,
+ FailureMessage)) != ReadFileResult::READ_OK) {
return r;
}
@@ -589,8 +623,8 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
include = cmStrCat(directory, '/', include);
}
- if ((result = includeFile(include, rootType, ReadReason::Included)) !=
- ReadFileResult::READ_OK) {
+ if ((result = includeFile(include, rootType, ReadReason::Included,
+ errMsg)) != ReadFileResult::READ_OK) {
return result;
}
}
@@ -599,7 +633,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
auto cmakePresetsFilename = GetFilename(this->SourceDir);
if (cmSystemTools::FileExists(cmakePresetsFilename)) {
if ((result = includeFile(cmakePresetsFilename, RootType::Project,
- ReadReason::Root)) !=
+ ReadReason::Root, errMsg)) !=
ReadFileResult::READ_OK) {
return result;
}
diff --git a/Source/cmCMakePresetsGraphReadJSONPackagePresets.cxx b/Source/cmCMakePresetsGraphReadJSONPackagePresets.cxx
new file mode 100644
index 0000000..4ae51b1
--- /dev/null
+++ b/Source/cmCMakePresetsGraphReadJSONPackagePresets.cxx
@@ -0,0 +1,95 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include <cstddef>
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+#include <cmext/string_view>
+
+#include <cm3p/json/value.h>
+
+#include "cmCMakePresetsGraph.h"
+#include "cmCMakePresetsGraphInternal.h"
+#include "cmJSONHelpers.h"
+
+namespace {
+using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
+using PackagePreset = cmCMakePresetsGraph::PackagePreset;
+
+auto const OutputHelper =
+ cmJSONHelperBuilder<ReadFileResult>::Object<PackagePreset>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+ .Bind("debug"_s, &PackagePreset::DebugOutput,
+ cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+ .Bind("verbose"_s, &PackagePreset::VerboseOutput,
+ cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false);
+
+auto const VariableHelper = cmJSONHelperBuilder<ReadFileResult>::String(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE);
+
+auto const VariablesHelper =
+ cmJSONHelperBuilder<ReadFileResult>::Map<std::string>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, VariableHelper);
+
+auto const PackagePresetHelper =
+ cmJSONHelperBuilder<ReadFileResult>::Object<PackagePreset>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+ .Bind("name"_s, &PackagePreset::Name,
+ cmCMakePresetsGraphInternal::PresetStringHelper)
+ .Bind("inherits"_s, &PackagePreset::Inherits,
+ cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper,
+ false)
+ .Bind("hidden"_s, &PackagePreset::Hidden,
+ cmCMakePresetsGraphInternal::PresetBoolHelper, false)
+ .Bind<std::nullptr_t>("vendor"_s, nullptr,
+ cmCMakePresetsGraphInternal::VendorHelper(
+ ReadFileResult::INVALID_PRESET),
+ false)
+ .Bind("displayName"_s, &PackagePreset::DisplayName,
+ cmCMakePresetsGraphInternal::PresetStringHelper, false)
+ .Bind("description"_s, &PackagePreset::Description,
+ cmCMakePresetsGraphInternal::PresetStringHelper, false)
+ .Bind("environment"_s, &PackagePreset::Environment,
+ cmCMakePresetsGraphInternal::EnvironmentMapHelper, false)
+ .Bind("configurePreset"_s, &PackagePreset::ConfigurePreset,
+ cmCMakePresetsGraphInternal::PresetStringHelper, false)
+ .Bind("inheritConfigureEnvironment"_s,
+ &PackagePreset::InheritConfigureEnvironment,
+ cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
+ .Bind("generators"_s, &PackagePreset::Generators,
+ cmCMakePresetsGraphInternal::PresetVectorStringHelper, false)
+ .Bind("configurations"_s, &PackagePreset::Configurations,
+ cmCMakePresetsGraphInternal::PresetVectorStringHelper, false)
+ .Bind("variables"_s, &PackagePreset::Variables, VariablesHelper, false)
+ .Bind("configFile"_s, &PackagePreset::ConfigFile,
+ cmCMakePresetsGraphInternal::PresetStringHelper, false)
+ .Bind("output"_s, OutputHelper, false)
+ .Bind("packageName"_s, &PackagePreset::PackageName,
+ cmCMakePresetsGraphInternal::PresetStringHelper, false)
+ .Bind("packageVersion"_s, &PackagePreset::PackageVersion,
+ cmCMakePresetsGraphInternal::PresetStringHelper, false)
+ .Bind("packageDirectory"_s, &PackagePreset::PackageDirectory,
+ cmCMakePresetsGraphInternal::PresetStringHelper, false)
+ .Bind("vendorName"_s, &PackagePreset::VendorName,
+ cmCMakePresetsGraphInternal::PresetStringHelper, false)
+ .Bind("condition"_s, &PackagePreset::ConditionEvaluator,
+ cmCMakePresetsGraphInternal::PresetConditionHelper, false);
+}
+
+namespace cmCMakePresetsGraphInternal {
+cmCMakePresetsGraph::ReadFileResult PackagePresetsHelper(
+ std::vector<cmCMakePresetsGraph::PackagePreset>& out,
+ const Json::Value* value)
+{
+ static auto const helper =
+ cmJSONHelperBuilder<ReadFileResult>::Vector<PackagePreset>(
+ ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
+ PackagePresetHelper);
+
+ return helper(out, value);
+}
+}
diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx
index c6296f9..27f2156 100644
--- a/Source/cmCommands.cxx
+++ b/Source/cmCommands.cxx
@@ -14,13 +14,13 @@
#include "cmAddLibraryCommand.h"
#include "cmAddSubDirectoryCommand.h"
#include "cmAddTestCommand.h"
+#include "cmBlockCommand.h"
#include "cmBreakCommand.h"
#include "cmBuildCommand.h"
#include "cmCMakeLanguageCommand.h"
#include "cmCMakeMinimumRequired.h"
#include "cmCMakePathCommand.h"
#include "cmCMakePolicyCommand.h"
-#include "cmCommand.h"
#include "cmConfigureFileCommand.h"
#include "cmContinueCommand.h"
#include "cmCreateTestSourceList.h"
@@ -127,6 +127,7 @@ void GetScriptingCommands(cmState* state)
state->AddFlowControlCommand("macro", cmMacroCommand);
state->AddFlowControlCommand("return", cmReturnCommand);
state->AddFlowControlCommand("while", cmWhileCommand);
+ state->AddFlowControlCommand("block", cmBlockCommand);
state->AddBuiltinCommand("cmake_language", cmCMakeLanguageCommand);
state->AddBuiltinCommand("cmake_minimum_required", cmCMakeMinimumRequired);
@@ -199,6 +200,10 @@ void GetScriptingCommands(cmState* state)
"An ENDWHILE command was found outside of a proper "
"WHILE ENDWHILE structure. Or its arguments did not "
"match the opening WHILE command.");
+ state->AddUnexpectedFlowControlCommand(
+ "endblock",
+ "An ENDBLOCK command was found outside of a proper "
+ "BLOCK ENDBLOCK structure.");
#if !defined(CMAKE_BOOTSTRAP)
state->AddBuiltinCommand("cmake_host_system_information",
@@ -220,6 +225,8 @@ void GetScriptingCommands(cmState* state)
void GetProjectCommands(cmState* state)
{
+ state->AddBuiltinCommand("add_compile_definitions",
+ cmAddCompileDefinitionsCommand);
state->AddBuiltinCommand("add_custom_command", cmAddCustomCommandCommand);
state->AddBuiltinCommand("add_custom_target", cmAddCustomTargetCommand);
state->AddBuiltinCommand("add_definitions", cmAddDefinitionsCommand);
@@ -264,15 +271,12 @@ void GetProjectCommands(cmState* state)
cmTargetLinkLibrariesCommand);
state->AddBuiltinCommand("target_link_options", cmTargetLinkOptionsCommand);
state->AddBuiltinCommand("target_sources", cmTargetSourcesCommand);
- state->AddBuiltinCommand("try_compile",
- cm::make_unique<cmTryCompileCommand>());
- state->AddBuiltinCommand("try_run", cm::make_unique<cmTryRunCommand>());
+ state->AddBuiltinCommand("try_compile", cmTryCompileCommand);
+ state->AddBuiltinCommand("try_run", cmTryRunCommand);
state->AddBuiltinCommand("target_precompile_headers",
cmTargetPrecompileHeadersCommand);
#if !defined(CMAKE_BOOTSTRAP)
- state->AddBuiltinCommand("add_compile_definitions",
- cmAddCompileDefinitionsCommand);
state->AddBuiltinCommand("add_compile_options", cmAddCompileOptionsCommand);
state->AddBuiltinCommand("aux_source_directory",
cmAuxSourceDirectoryCommand);
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index e156e3d..044f69f 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -368,6 +368,10 @@ cmComputeLinkInformation::cmComputeLinkInformation(
LibraryFeatureDescriptor{ "__CMAKE_LINK_EXECUTABLE",
cmStrCat(this->LoaderFlag, "<LIBRARY>") });
}
+ // To link framewortk using a full path
+ this->LibraryFeatureDescriptors.emplace(
+ "__CMAKE_LINK_FRAMEWORK",
+ LibraryFeatureDescriptor{ "__CMAKE_LINK_FRAMEWORK", "<LIBRARY>" });
// Check the platform policy for missing soname case.
this->NoSONameUsesPath =
@@ -549,6 +553,17 @@ bool cmComputeLinkInformation::Compute()
if (linkEntry.Kind == cmComputeLinkDepends::LinkEntry::Group) {
const auto& groupFeature = this->GetGroupFeature(linkEntry.Feature);
if (groupFeature.Supported) {
+ if (linkEntry.Item.Value == "</LINK_GROUP>" &&
+ currentFeature != nullptr) {
+ // emit feature suffix, if any
+ if (!currentFeature->Suffix.empty()) {
+ this->Items.emplace_back(
+ BT<std::string>{ currentFeature->Suffix,
+ this->Items.back().Value.Backtrace },
+ ItemIsPath::No);
+ }
+ currentFeature = nullptr;
+ }
this->Items.emplace_back(
BT<std::string>{ linkEntry.Item.Value == "<LINK_GROUP>"
? groupFeature.Prefix
@@ -1549,16 +1564,11 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry)
this->OldLinkDirItems.push_back(item.Value);
}
- if (target->IsFrameworkOnApple() && this->GlobalGenerator->IsXcode() &&
- entry.Feature == DEFAULT) {
- // ensure FRAMEWORK feature is loaded
- this->AddLibraryFeature("FRAMEWORK");
- }
-
if (target->IsFrameworkOnApple() && !this->GlobalGenerator->IsXcode()) {
// Add the framework directory and the framework item itself
- auto fwItems = this->GlobalGenerator->SplitFrameworkPath(item.Value, true);
- if (!fwItems) {
+ auto fwDescriptor = this->GlobalGenerator->SplitFrameworkPath(
+ item.Value, cmGlobalGenerator::FrameworkFormat::Extended);
+ if (!fwDescriptor) {
this->CMakeInstance->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("Could not parse framework path \"", item.Value,
@@ -1566,12 +1576,13 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry)
item.Backtrace);
return;
}
- if (!fwItems->first.empty()) {
+ if (!fwDescriptor->Directory.empty()) {
// Add the directory portion to the framework search path.
- this->AddFrameworkPath(fwItems->first);
+ this->AddFrameworkPath(fwDescriptor->Directory);
}
if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s)) {
- this->Items.emplace_back(fwItems->second, ItemIsPath::Yes, target,
+ this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes,
+ target,
this->FindLibraryFeature(entry.Feature));
} else {
this->Items.emplace_back(
@@ -1586,7 +1597,7 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry)
this->FindLibraryFeature(
entry.Feature == DEFAULT
? (target->IsFrameworkOnApple() && this->GlobalGenerator->IsXcode()
- ? "FRAMEWORK"
+ ? "__CMAKE_LINK_FRAMEWORK"
: "__CMAKE_LINK_LIBRARY")
: entry.Feature));
}
@@ -1842,9 +1853,11 @@ void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
std::string const& item = entry.Item.Value;
// Try to separate the framework name and path.
- auto fwItems =
- this->GlobalGenerator->SplitFrameworkPath(item, entry.Feature != DEFAULT);
- if (!fwItems) {
+ auto fwDescriptor = this->GlobalGenerator->SplitFrameworkPath(
+ item,
+ entry.Feature == DEFAULT ? cmGlobalGenerator::FrameworkFormat::Relaxed
+ : cmGlobalGenerator::FrameworkFormat::Extended);
+ if (!fwDescriptor) {
std::ostringstream e;
e << "Could not parse framework path \"" << item << "\" "
<< "linked by target " << this->Target->GetName() << ".";
@@ -1852,18 +1865,14 @@ void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
return;
}
- std::string fw_path = std::move(fwItems->first);
- std::string fw = std::move(fwItems->second);
- std::string full_fw = cmStrCat(fw, ".framework/", fw);
-
+ const std::string& fw_path = fwDescriptor->Directory;
if (!fw_path.empty()) {
- full_fw = cmStrCat(fw_path, '/', full_fw);
// Add the directory portion to the framework search path.
this->AddFrameworkPath(fw_path);
}
// add runtime information
- this->AddLibraryRuntimeInfo(full_fw);
+ this->AddLibraryRuntimeInfo(fwDescriptor->GetFullPath());
if (entry.Feature == DEFAULT) {
// ensure FRAMEWORK feature is loaded
@@ -1878,9 +1887,9 @@ void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
? "FRAMEWORK"
: entry.Feature));
} else {
- this->Items.emplace_back(fw, ItemIsPath::Yes, nullptr,
- this->FindLibraryFeature(entry.Feature == DEFAULT
- ? "FRAMEWORK"
+ this->Items.emplace_back(
+ fwDescriptor->GetLinkName(), ItemIsPath::Yes, nullptr,
+ this->FindLibraryFeature(entry.Feature == DEFAULT ? "FRAMEWORK"
: entry.Feature));
}
}
@@ -2243,15 +2252,11 @@ void cmComputeLinkInformation::AddLibraryRuntimeInfo(
// It could be an Apple framework
if (!is_shared_library) {
- if (fullPath.find(".framework") != std::string::npos) {
- static cmsys::RegularExpression splitFramework(
- "^(.*)/(.*).framework/(.*)$");
- if (splitFramework.find(fullPath) &&
- (std::string::npos !=
- splitFramework.match(3).find(splitFramework.match(2)))) {
- is_shared_library = true;
- }
- }
+ is_shared_library =
+ this->GlobalGenerator
+ ->SplitFrameworkPath(fullPath,
+ cmGlobalGenerator::FrameworkFormat::Strict)
+ .has_value();
}
if (!is_shared_library) {
diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in
index 6a419f6..90f3de0 100644
--- a/Source/cmConfigure.cmake.h.in
+++ b/Source/cmConfigure.cmake.h.in
@@ -14,10 +14,15 @@
#pragma warning(disable : 1572) /* floating-point equality test */
#endif
+#if defined(__LCC__) && defined(__EDG__) && (__LCC__ == 123)
+#pragma diag_suppress 2910 /* excess -Wunused-function in 1.23.x */
+#endif
+
#cmakedefine HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE
#cmakedefine HAVE_UNSETENV
#cmakedefine CMake_USE_MACH_PARSER
#cmakedefine CMake_USE_XCOFF_PARSER
+#cmakedefine CMAKE_USE_WMAKE
#define CMake_DEFAULT_RECURSION_LIMIT @CMake_DEFAULT_RECURSION_LIMIT@
#define CMAKE_BIN_DIR "/@CMAKE_BIN_DIR@"
#define CMAKE_DATA_DIR "/@CMAKE_DATA_DIR@"
@@ -28,3 +33,11 @@
#if defined(_WIN32) && !defined(NOMINMAX)
# define NOMINMAX
#endif
+
+#cmakedefine CURL_CA_BUNDLE "@CURL_CA_BUNDLE@"
+#cmakedefine CURL_CA_PATH "@CURL_CA_PATH@"
+
+#cmakedefine01 CMake_STAT_HAS_ST_MTIM
+#cmakedefine01 CMake_STAT_HAS_ST_MTIMESPEC
+
+#cmakedefine KWSYS_ENCODING_DEFAULT_CODEPAGE @KWSYS_ENCODING_DEFAULT_CODEPAGE@
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 45afdd1..f40b3e9 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCoreTryCompile.h"
+#include <array>
#include <cstdio>
#include <cstring>
#include <set>
@@ -12,13 +13,16 @@
#include <cmext/string_view>
#include "cmsys/Directory.hxx"
+#include "cmsys/FStream.hxx"
+#include "cmArgumentParser.h"
#include "cmExportTryCompileFileGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmOutputConverter.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmState.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
@@ -28,142 +32,7 @@
#include "cmake.h"
namespace {
-class LanguageStandardState
-{
-public:
- LanguageStandardState(std::string&& lang)
- : 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.emplace_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 = false;
- bool DidStandard = false;
- bool DidStandardRequired = false;
- bool DidExtensions = false;
-
- std::string StandardFlag;
- std::string RequiredFlag;
- std::string ExtensionFlag;
-
- std::string StandardValue;
- std::string RequiredValue;
- std::string ExtensionValue;
-};
-
+constexpr const char* unique_binary_directory = "CMAKE_BINARY_DIR_USE_MKDTEMP";
constexpr size_t lang_property_start = 0;
constexpr size_t lang_property_size = 4;
constexpr size_t pie_property_start = 4;
@@ -226,6 +95,8 @@ std::string const kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES =
std::string const kCMAKE_WARN_DEPRECATED = "CMAKE_WARN_DEPRECATED";
std::string const kCMAKE_WATCOM_RUNTIME_LIBRARY_DEFAULT =
"CMAKE_WATCOM_RUNTIME_LIBRARY_DEFAULT";
+std::string const kCMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT =
+ "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT";
/* GHS Multi platform variables */
std::set<std::string> const ghs_platform_vars{
@@ -233,114 +104,248 @@ std::set<std::string> const ghs_platform_vars{
"GHS_OS_ROOT", "GHS_OS_DIR", "GHS_BSP_NAME",
"GHS_OS_DIR_OPTION"
};
+using Arguments = cmCoreTryCompile::Arguments;
+
+ArgumentParser::Continue TryCompileLangProp(Arguments& args,
+ cm::string_view key,
+ cm::string_view val)
+{
+ args.LangProps[std::string(key)] = std::string(val);
+ return ArgumentParser::Continue::No;
}
-int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
- bool isTryRun)
+ArgumentParser::Continue TryCompileCompileDefs(Arguments& args,
+ cm::string_view val)
+{
+ cmExpandList(val, args.CompileDefs);
+ return ArgumentParser::Continue::Yes;
+}
+
+cmArgumentParser<Arguments> makeTryCompileParser(
+ const cmArgumentParser<Arguments>& base)
+{
+ return cmArgumentParser<Arguments>{ base }.Bind("OUTPUT_VARIABLE"_s,
+ &Arguments::OutputVariable);
+}
+
+cmArgumentParser<Arguments> makeTryRunParser(
+ const cmArgumentParser<Arguments>& base)
+{
+ return cmArgumentParser<Arguments>{ base }
+ .Bind("COMPILE_OUTPUT_VARIABLE"_s, &Arguments::CompileOutputVariable)
+ .Bind("RUN_OUTPUT_VARIABLE"_s, &Arguments::RunOutputVariable)
+ .Bind("RUN_OUTPUT_STDOUT_VARIABLE"_s, &Arguments::RunOutputStdOutVariable)
+ .Bind("RUN_OUTPUT_STDERR_VARIABLE"_s, &Arguments::RunOutputStdErrVariable)
+ .Bind("WORKING_DIRECTORY"_s, &Arguments::RunWorkingDirectory)
+ .Bind("ARGS"_s, &Arguments::RunArgs)
+ /* keep semicolon on own line */;
+}
+
+#define BIND_LANG_PROPS(lang) \
+ Bind(#lang "_STANDARD"_s, TryCompileLangProp) \
+ .Bind(#lang "_STANDARD_REQUIRED"_s, TryCompileLangProp) \
+ .Bind(#lang "_EXTENSIONS"_s, TryCompileLangProp)
+
+auto const TryCompileBaseArgParser =
+ cmArgumentParser<Arguments>{}
+ .Bind(0, &Arguments::CompileResultVariable)
+ .Bind("CMAKE_FLAGS"_s, &Arguments::CMakeFlags)
+ .Bind("__CMAKE_INTERNAL"_s, &Arguments::CMakeInternal)
+ /* keep semicolon on own line */;
+
+auto const TryCompileBaseSourcesArgParser =
+ cmArgumentParser<Arguments>{ TryCompileBaseArgParser }
+ .Bind("SOURCES"_s, &Arguments::Sources)
+ .Bind("COMPILE_DEFINITIONS"_s, TryCompileCompileDefs,
+ ArgumentParser::ExpectAtLeast{ 0 })
+ .Bind("LINK_LIBRARIES"_s, &Arguments::LinkLibraries)
+ .Bind("LINK_OPTIONS"_s, &Arguments::LinkOptions)
+ .Bind("COPY_FILE"_s, &Arguments::CopyFileTo)
+ .Bind("COPY_FILE_ERROR"_s, &Arguments::CopyFileError)
+ .BIND_LANG_PROPS(C)
+ .BIND_LANG_PROPS(CUDA)
+ .BIND_LANG_PROPS(CXX)
+ .BIND_LANG_PROPS(HIP)
+ .BIND_LANG_PROPS(OBJC)
+ .BIND_LANG_PROPS(OBJCXX)
+ /* keep semicolon on own line */;
+
+auto const TryCompileBaseNewSourcesArgParser =
+ cmArgumentParser<Arguments>{ TryCompileBaseSourcesArgParser }
+ .Bind("SOURCE_FROM_ARG"_s, &Arguments::SourceFromArg)
+ .Bind("SOURCE_FROM_VAR"_s, &Arguments::SourceFromVar)
+ .Bind("SOURCE_FROM_FILE"_s, &Arguments::SourceFromFile)
+ /* keep semicolon on own line */;
+
+auto const TryCompileBaseProjectArgParser =
+ cmArgumentParser<Arguments>{ TryCompileBaseArgParser }
+ .Bind("PROJECT"_s, &Arguments::ProjectName)
+ .Bind("SOURCE_DIR"_s, &Arguments::SourceDirectoryOrFile)
+ .Bind("BINARY_DIR"_s, &Arguments::BinaryDirectory)
+ .Bind("TARGET"_s, &Arguments::TargetName)
+ /* keep semicolon on own line */;
+
+auto const TryCompileProjectArgParser =
+ makeTryCompileParser(TryCompileBaseProjectArgParser);
+
+auto const TryCompileSourcesArgParser =
+ makeTryCompileParser(TryCompileBaseNewSourcesArgParser);
+
+auto const TryCompileOldArgParser =
+ makeTryCompileParser(TryCompileBaseSourcesArgParser)
+ .Bind(1, &Arguments::BinaryDirectory)
+ .Bind(2, &Arguments::SourceDirectoryOrFile)
+ .Bind(3, &Arguments::ProjectName)
+ .Bind(4, &Arguments::TargetName)
+ /* keep semicolon on own line */;
+
+auto const TryRunSourcesArgParser =
+ makeTryRunParser(TryCompileBaseNewSourcesArgParser);
+
+auto const TryRunOldArgParser = makeTryRunParser(TryCompileOldArgParser);
+
+#undef BIND_LANG_PROPS
+}
+
+Arguments cmCoreTryCompile::ParseArgs(
+ const cmRange<std::vector<std::string>::const_iterator>& args,
+ const cmArgumentParser<Arguments>& parser,
+ std::vector<std::string>& unparsedArguments)
+{
+ auto arguments = parser.Parse(args, &unparsedArguments, 0);
+ if (!arguments.MaybeReportError(*(this->Makefile)) &&
+ !unparsedArguments.empty()) {
+ std::string m = "Unknown arguments:";
+ for (const auto& i : unparsedArguments) {
+ m = cmStrCat(m, "\n \"", i, "\"");
+ }
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, m);
+ }
+ return arguments;
+}
+
+Arguments cmCoreTryCompile::ParseArgs(
+ cmRange<std::vector<std::string>::const_iterator> args, bool isTryRun)
+{
+ std::vector<std::string> unparsedArguments;
+ const auto& second = *(++args.begin());
+
+ if (!isTryRun && second == "PROJECT") {
+ // New PROJECT signature (try_compile only).
+ auto arguments =
+ this->ParseArgs(args, TryCompileProjectArgParser, unparsedArguments);
+ if (!arguments.BinaryDirectory) {
+ arguments.BinaryDirectory = unique_binary_directory;
+ }
+ return arguments;
+ }
+
+ if (cmHasLiteralPrefix(second, "SOURCE")) {
+ // New SOURCES signature.
+ auto arguments = this->ParseArgs(
+ args, isTryRun ? TryRunSourcesArgParser : TryCompileSourcesArgParser,
+ unparsedArguments);
+ arguments.BinaryDirectory = unique_binary_directory;
+ return arguments;
+ }
+
+ // Old signature.
+ auto arguments = this->ParseArgs(
+ args, isTryRun ? TryRunOldArgParser : TryCompileOldArgParser,
+ unparsedArguments);
+ // For historical reasons, treat some empty-valued keyword
+ // arguments as if they were not specified at all.
+ if (arguments.OutputVariable && arguments.OutputVariable->empty()) {
+ arguments.OutputVariable = cm::nullopt;
+ }
+ if (isTryRun) {
+ if (arguments.CompileOutputVariable &&
+ arguments.CompileOutputVariable->empty()) {
+ arguments.CompileOutputVariable = cm::nullopt;
+ }
+ if (arguments.RunOutputVariable && arguments.RunOutputVariable->empty()) {
+ arguments.RunOutputVariable = cm::nullopt;
+ }
+ if (arguments.RunOutputStdOutVariable &&
+ arguments.RunOutputStdOutVariable->empty()) {
+ arguments.RunOutputStdOutVariable = cm::nullopt;
+ }
+ if (arguments.RunOutputStdErrVariable &&
+ arguments.RunOutputStdErrVariable->empty()) {
+ arguments.RunOutputStdErrVariable = cm::nullopt;
+ }
+ if (arguments.RunWorkingDirectory &&
+ arguments.RunWorkingDirectory->empty()) {
+ arguments.RunWorkingDirectory = cm::nullopt;
+ }
+ }
+ return arguments;
+}
+
+bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
+ cmStateEnums::TargetType targetType)
{
- this->BinaryDirectory = argv[1];
this->OutputFile.clear();
// which signature were we called with ?
this->SrcFileSignature = true;
- cmStateEnums::TargetType targetType = cmStateEnums::EXECUTABLE;
- cmValue tt = this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_TARGET_TYPE");
- if (!isTryRun && cmNonempty(tt)) {
- if (*tt == cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE)) {
- targetType = cmStateEnums::EXECUTABLE;
- } else if (*tt ==
- cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY)) {
- targetType = cmStateEnums::STATIC_LIBRARY;
- } else {
+ bool useUniqueBinaryDirectory = false;
+ std::string sourceDirectory;
+ std::string projectName;
+ std::string targetName;
+ if (arguments.ProjectName) {
+ this->SrcFileSignature = false;
+ if (!arguments.SourceDirectoryOrFile ||
+ arguments.SourceDirectoryOrFile->empty()) {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ "No <srcdir> specified.");
+ return false;
+ }
+ sourceDirectory = *arguments.SourceDirectoryOrFile;
+ projectName = *arguments.ProjectName;
+ if (arguments.TargetName) {
+ targetName = *arguments.TargetName;
+ }
+ } else {
+ projectName = "CMAKE_TRY_COMPILE";
+ /* Use a random file name to avoid rapid creation and deletion
+ of the same executable name (some filesystems fail on that). */
+ char targetNameBuf[64];
+ snprintf(targetNameBuf, sizeof(targetNameBuf), "cmTC_%05x",
+ cmSystemTools::RandomSeed() & 0xFFFFF);
+ targetName = targetNameBuf;
+ }
+
+ if (!arguments.BinaryDirectory || arguments.BinaryDirectory->empty()) {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ "No <bindir> specified.");
+ return false;
+ }
+ if (*arguments.BinaryDirectory == unique_binary_directory) {
+ // leave empty until we're ready to create it, so we don't try to remove
+ // a non-existing directory if we abort due to e.g. bad arguments
+ this->BinaryDirectory.clear();
+ useUniqueBinaryDirectory = true;
+ } else {
+ if (!cmSystemTools::FileIsFullPath(*arguments.BinaryDirectory)) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
- cmStrCat("Invalid value '", *tt,
- "' for CMAKE_TRY_COMPILE_TARGET_TYPE. Only '",
- cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE),
- "' and '",
- cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY),
- "' are allowed."));
- return -1;
+ cmStrCat("<bindir> is not an absolute path:\n '",
+ *arguments.BinaryDirectory, "'"));
+ return false;
+ }
+ this->BinaryDirectory = *arguments.BinaryDirectory;
+ // compute the binary dir when TRY_COMPILE is called with a src file
+ // signature
+ if (this->SrcFileSignature) {
+ this->BinaryDirectory += "/CMakeFiles/CMakeTmp";
}
}
- std::string sourceDirectory = argv[2];
- std::string projectName;
- std::string targetName;
- std::vector<std::string> cmakeFlags(1, "CMAKE_FLAGS"); // fake argv[0]
- std::vector<std::string> compileDefs;
- std::string cmakeInternal;
- std::string outputVariable;
- std::string copyFile;
- std::string copyFileError;
- LanguageStandardState cState("C");
- LanguageStandardState cudaState("CUDA");
- LanguageStandardState cxxState("CXX");
- LanguageStandardState hipState("HIP");
- LanguageStandardState objcState("OBJC");
- LanguageStandardState objcxxState("OBJCXX");
std::vector<std::string> targets;
- std::vector<std::string> linkOptions;
- std::string libsToLink = " ";
- bool useOldLinkLibs = true;
- char targetNameBuf[64];
- bool didOutputVariable = false;
- bool didCopyFile = false;
- bool didCopyFileError = false;
- bool useSources = argv[2] == "SOURCES";
- std::vector<std::string> sources;
-
- enum Doing
- {
- DoingNone,
- DoingCMakeFlags,
- DoingCompileDefinitions,
- DoingLinkOptions,
- DoingLinkLibraries,
- DoingOutputVariable,
- DoingCopyFile,
- DoingCopyFileError,
- DoingSources,
- DoingCMakeInternal
- };
- Doing doing = useSources ? DoingSources : DoingNone;
- for (size_t i = 3; i < argv.size(); ++i) {
- if (argv[i] == "CMAKE_FLAGS") {
- doing = DoingCMakeFlags;
- } else if (argv[i] == "COMPILE_DEFINITIONS") {
- doing = DoingCompileDefinitions;
- } else if (argv[i] == "LINK_OPTIONS") {
- doing = DoingLinkOptions;
- } else if (argv[i] == "LINK_LIBRARIES") {
- doing = DoingLinkLibraries;
- useOldLinkLibs = false;
- } else if (argv[i] == "OUTPUT_VARIABLE") {
- doing = DoingOutputVariable;
- didOutputVariable = true;
- } else if (argv[i] == "COPY_FILE") {
- doing = DoingCopyFile;
- didCopyFile = true;
- } else if (argv[i] == "COPY_FILE_ERROR") {
- doing = DoingCopyFileError;
- didCopyFileError = true;
- } else if (cState.UpdateIfMatches(argv, i) ||
- cxxState.UpdateIfMatches(argv, i) ||
- cudaState.UpdateIfMatches(argv, i) ||
- hipState.UpdateIfMatches(argv, i) ||
- objcState.UpdateIfMatches(argv, i) ||
- objcxxState.UpdateIfMatches(argv, i)) {
- continue;
- } else if (argv[i] == "__CMAKE_INTERNAL") {
- doing = DoingCMakeInternal;
- } else if (doing == DoingCMakeFlags) {
- cmakeFlags.emplace_back(argv[i]);
- } else if (doing == DoingCompileDefinitions) {
- cmExpandList(argv[i], compileDefs);
- } else if (doing == DoingLinkOptions) {
- linkOptions.emplace_back(argv[i]);
- } else if (doing == DoingLinkLibraries) {
- libsToLink += "\"" + cmTrimWhitespace(argv[i]) + "\" ";
- if (cmTarget* tgt = this->Makefile->FindTargetToUse(argv[i])) {
+ if (arguments.LinkLibraries) {
+ for (std::string const& i : *arguments.LinkLibraries) {
+ if (cmTarget* tgt = this->Makefile->FindTargetToUse(i)) {
switch (tgt->GetType()) {
case cmStateEnums::SHARED_LIBRARY:
case cmStateEnums::STATIC_LIBRARY:
@@ -359,114 +364,93 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
"IMPORTED LINK_LIBRARIES. Got ",
tgt->GetName(), " of type ",
cmState::GetTargetTypeName(tgt->GetType()), "."));
- return -1;
+ return false;
}
if (tgt->IsImported()) {
- targets.emplace_back(argv[i]);
+ targets.emplace_back(i);
}
}
- } else if (doing == DoingOutputVariable) {
- outputVariable = argv[i];
- doing = DoingNone;
- } else if (doing == DoingCopyFile) {
- copyFile = argv[i];
- doing = DoingNone;
- } else if (doing == DoingCopyFileError) {
- copyFileError = argv[i];
- doing = DoingNone;
- } else if (doing == DoingSources) {
- sources.emplace_back(argv[i]);
- } else if (doing == DoingCMakeInternal) {
- cmakeInternal = argv[i];
- doing = DoingNone;
- } else if (i == 3) {
- this->SrcFileSignature = false;
- projectName = argv[i];
- } else if (i == 4 && !this->SrcFileSignature) {
- targetName = argv[i];
- } else {
- std::ostringstream m;
- m << "try_compile given unknown argument \"" << argv[i] << "\".";
- this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, m.str());
}
}
- if (didCopyFile && copyFile.empty()) {
+ if (arguments.CopyFileTo && arguments.CopyFileTo->empty()) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
"COPY_FILE must be followed by a file path");
- return -1;
+ return false;
}
- if (didCopyFileError && copyFileError.empty()) {
+ if (arguments.CopyFileError && arguments.CopyFileError->empty()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"COPY_FILE_ERROR must be followed by a variable name");
- return -1;
+ return false;
}
- if (didCopyFileError && !didCopyFile) {
+ if (arguments.CopyFileError && !arguments.CopyFileTo) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"COPY_FILE_ERROR may be used only with COPY_FILE");
- return -1;
- }
-
- if (didOutputVariable && outputVariable.empty()) {
- this->Makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- "OUTPUT_VARIABLE must be followed by a variable name");
- return -1;
+ return false;
}
- if (useSources && sources.empty()) {
+ if (arguments.Sources && arguments.Sources->empty()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"SOURCES must be followed by at least one source file");
- return -1;
+ return false;
}
- if (!this->SrcFileSignature) {
- if (!cState.Validate(this->Makefile)) {
- return -1;
- }
- if (!cudaState.Validate(this->Makefile)) {
- return -1;
- }
- if (!hipState.Validate(this->Makefile)) {
- return -1;
- }
- if (!cxxState.Validate(this->Makefile)) {
- return -1;
+ if (this->SrcFileSignature) {
+ if (arguments.SourceFromArg && arguments.SourceFromArg->size() % 2) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "SOURCE_FROM_ARG requires exactly two arguments");
+ return false;
}
- if (!objcState.Validate(this->Makefile)) {
- return -1;
+ if (arguments.SourceFromVar && arguments.SourceFromVar->size() % 2) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "SOURCE_FROM_VAR requires exactly two arguments");
+ return false;
}
- if (!objcxxState.Validate(this->Makefile)) {
- return -1;
+ if (arguments.SourceFromFile && arguments.SourceFromFile->size() % 2) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "SOURCE_FROM_FILE requires exactly two arguments");
+ return false;
}
- }
-
- // compute the binary dir when TRY_COMPILE is called with a src file
- // signature
- if (this->SrcFileSignature) {
- this->BinaryDirectory += "/CMakeFiles/CMakeTmp";
} else {
// only valid for srcfile signatures
- if (!compileDefs.empty()) {
+ if (!arguments.LangProps.empty()) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(arguments.LangProps.begin()->first,
+ " allowed only in source file signature"));
+ return false;
+ }
+ if (!arguments.CompileDefs.empty()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
- "COMPILE_DEFINITIONS specified on a srcdir type TRY_COMPILE");
- return -1;
+ "COMPILE_DEFINITIONS allowed only in source file signature");
+ return false;
}
- if (!copyFile.empty()) {
+ if (arguments.CopyFileTo) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
- "COPY_FILE specified on a srcdir type TRY_COMPILE");
- return -1;
+ "COPY_FILE allowed only in source file signature");
+ return false;
}
}
+
// make sure the binary directory exists
- cmSystemTools::MakeDirectory(this->BinaryDirectory);
+ if (useUniqueBinaryDirectory) {
+ this->BinaryDirectory =
+ cmStrCat(this->Makefile->GetHomeOutputDirectory(),
+ "/CMakeFiles/CMakeScratch/TryCompile-XXXXXX");
+ cmSystemTools::MakeTempDirectory(this->BinaryDirectory);
+ } else {
+ cmSystemTools::MakeDirectory(this->BinaryDirectory);
+ }
// do not allow recursive try Compiles
if (this->BinaryDirectory == this->Makefile->GetHomeOutputDirectory()) {
@@ -474,7 +458,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
e << "Attempt at a recursive or nested TRY_COMPILE in directory\n"
<< " " << this->BinaryDirectory << "\n";
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
- return -1;
+ return false;
}
std::string outFileName = this->BinaryDirectory + "/CMakeLists.txt";
@@ -485,9 +469,63 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
cmSystemTools::RemoveFile(ccFile);
// Choose sources.
- if (!useSources) {
- sources.emplace_back(argv[2]);
+ std::vector<std::string> sources;
+ if (arguments.Sources) {
+ sources = std::move(*arguments.Sources);
+ } else if (arguments.SourceDirectoryOrFile) {
+ sources.emplace_back(*arguments.SourceDirectoryOrFile);
+ }
+ if (arguments.SourceFromArg) {
+ auto const k = arguments.SourceFromArg->size();
+ for (auto i = decltype(k){ 0 }; i < k; i += 2) {
+ const auto& name = (*arguments.SourceFromArg)[i + 0];
+ const auto& content = (*arguments.SourceFromArg)[i + 1];
+ auto out = this->WriteSource(name, content, "SOURCES_FROM_ARG");
+ if (out.empty()) {
+ return false;
+ }
+ sources.emplace_back(std::move(out));
+ }
+ }
+ if (arguments.SourceFromVar) {
+ auto const k = arguments.SourceFromVar->size();
+ for (auto i = decltype(k){ 0 }; i < k; i += 2) {
+ const auto& name = (*arguments.SourceFromVar)[i + 0];
+ const auto& var = (*arguments.SourceFromVar)[i + 1];
+ const auto& content = this->Makefile->GetDefinition(var);
+ auto out = this->WriteSource(name, content, "SOURCES_FROM_VAR");
+ if (out.empty()) {
+ return false;
+ }
+ sources.emplace_back(std::move(out));
+ }
}
+ if (arguments.SourceFromFile) {
+ auto const k = arguments.SourceFromFile->size();
+ for (auto i = decltype(k){ 0 }; i < k; i += 2) {
+ const auto& dst = (*arguments.SourceFromFile)[i + 0];
+ const auto& src = (*arguments.SourceFromFile)[i + 1];
+
+ if (!cmSystemTools::GetFilenamePath(dst).empty()) {
+ const auto& msg =
+ cmStrCat("SOURCE_FROM_FILE given invalid filename \"", dst, "\"");
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
+ return false;
+ }
+
+ auto dstPath = cmStrCat(this->BinaryDirectory, "/", dst);
+ auto const result = cmSystemTools::CopyFileAlways(src, dstPath);
+ if (!result.IsSuccess()) {
+ const auto& msg = cmStrCat("SOURCE_FROM_FILE failed to copy \"", src,
+ "\": ", result.GetString());
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
+ return false;
+ }
+
+ sources.emplace_back(std::move(dstPath));
+ }
+ }
+ // TODO: ensure sources is not empty
// Detect languages to enable.
cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
@@ -508,7 +546,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
err << cmJoin(langs, " ");
err << "\nSee project() command to enable other languages.";
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, err.str());
- return -1;
+ return false;
}
}
@@ -535,7 +573,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
<< cmSystemTools::GetLastSystemError();
/* clang-format on */
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
- return -1;
+ return false;
}
cmValue def = this->Makefile->GetDefinition("CMAKE_MODULE_PATH");
@@ -575,6 +613,14 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
*cmp0123 == "NEW"_s ? "NEW" : "OLD");
}
+ /* Set MSVC debug information format policy to match our selection. */
+ if (cmValue msvcDebugInformationFormatDefault =
+ this->Makefile->GetDefinition(
+ kCMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT)) {
+ fprintf(fout, "cmake_policy(SET CMP0141 %s)\n",
+ !msvcDebugInformationFormatDefault->empty() ? "NEW" : "OLD");
+ }
+
/* Set cache/normal variable policy to match outer project.
It may affect toolchain files. */
if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0126) !=
@@ -598,7 +644,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
}
}
fprintf(fout, "project(CMAKE_TRY_COMPILE%s)\n", projectLangs.c_str());
- if (cmakeInternal == "ABI") {
+ if (arguments.CMakeInternal == "ABI") {
// This is the ABI detection step, also used for implicit includes.
// Erase any include_directories() calls from the toolchain file so
// that we do not see them as implicit. Our ABI detection source
@@ -705,18 +751,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
fprintf(fout, "set(CMAKE_SUPPRESS_REGENERATION 1)\n");
fprintf(fout, "link_directories(${LINK_DIRECTORIES})\n");
// handle any compile flags we need to pass on
- if (!compileDefs.empty()) {
+ if (!arguments.CompileDefs.empty()) {
// Pass using bracket arguments to preserve content.
fprintf(fout, "add_definitions([==[%s]==])\n",
- cmJoin(compileDefs, "]==] [==[").c_str());
+ cmJoin(arguments.CompileDefs, "]==] [==[").c_str());
}
- /* Use a random file name to avoid rapid creation and deletion
- of the same executable name (some filesystems fail on that). */
- snprintf(targetNameBuf, sizeof(targetNameBuf), "cmTC_%05x",
- cmSystemTools::RandomSeed() & 0xFFFFF);
- targetName = targetNameBuf;
-
if (!targets.empty()) {
std::string fname = "/" + std::string(targetName) + "Targets.cmake";
cmExportTryCompileFileGenerator tcfg(gg, targets, this->Makefile,
@@ -728,7 +768,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
"could not write export file.");
fclose(fout);
- return -1;
+ return false;
}
fprintf(fout, "\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/%s\")\n\n",
fname.c_str());
@@ -772,24 +812,27 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
fprintf(fout, " \"%s\"", si.c_str());
// Add dependencies on any non-temporary sources.
- if (si.find("CMakeTmp") == std::string::npos) {
+ if (!IsTemporary(si)) {
this->Makefile->AddCMakeDependFile(si);
}
}
fprintf(fout, ")\n");
- cState.Enabled(testLangs.find("C") != testLangs.end());
- cxxState.Enabled(testLangs.find("CXX") != testLangs.end());
- cudaState.Enabled(testLangs.find("CUDA") != testLangs.end());
- hipState.Enabled(testLangs.find("HIP") != testLangs.end());
- objcState.Enabled(testLangs.find("OBJC") != testLangs.end());
- objcxxState.Enabled(testLangs.find("OBJCXX") != testLangs.end());
+ /* Write out the output location of the target we are building */
+ std::string perConfigGenex;
+ if (this->Makefile->GetGlobalGenerator()->IsMultiConfig()) {
+ perConfigGenex = "_$<UPPER_CASE:$<CONFIG>>";
+ }
+ fprintf(fout,
+ "file(GENERATE OUTPUT "
+ "\"${CMAKE_BINARY_DIR}/%s%s_loc\"\n",
+ targetName.c_str(), perConfigGenex.c_str());
+ fprintf(fout, " CONTENT $<TARGET_FILE:%s>)\n", targetName.c_str());
bool warnCMP0067 = false;
bool honorStandard = true;
- if (cState.DidNone() && cxxState.DidNone() && objcState.DidNone() &&
- objcxxState.DidNone() && cudaState.DidNone() && hipState.DidNone()) {
+ if (arguments.LangProps.empty()) {
switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0067)) {
case cmPolicies::WARN:
warnCMP0067 = this->Makefile->PolicyOptionalWarningEnabled(
@@ -814,18 +857,33 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
std::vector<std::string> warnCMP0067Variables;
- cState.LoadUnsetPropertyValues(this->Makefile, honorStandard, warnCMP0067,
- warnCMP0067Variables);
- cxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
- warnCMP0067, warnCMP0067Variables);
- cudaState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
- warnCMP0067, warnCMP0067Variables);
- hipState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
- warnCMP0067, warnCMP0067Variables);
- objcState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
- warnCMP0067, warnCMP0067Variables);
- objcxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
- warnCMP0067, warnCMP0067Variables);
+ if (honorStandard || warnCMP0067) {
+ static std::array<std::string, 6> const possibleLangs{
+ { "C", "CXX", "CUDA", "HIP", "OBJC", "OBJCXX" }
+ };
+ static std::array<cm::string_view, 3> const langPropSuffixes{
+ { "_STANDARD"_s, "_STANDARD_REQUIRED"_s, "_EXTENSIONS"_s }
+ };
+ for (std::string const& lang : possibleLangs) {
+ if (testLangs.find(lang) == testLangs.end()) {
+ continue;
+ }
+ for (cm::string_view propSuffix : langPropSuffixes) {
+ std::string langProp = cmStrCat(lang, propSuffix);
+ if (!arguments.LangProps.count(langProp)) {
+ std::string langPropVar = cmStrCat("CMAKE_"_s, langProp);
+ std::string value = this->Makefile->GetSafeDefinition(langPropVar);
+ if (warnCMP0067 && !value.empty()) {
+ value.clear();
+ warnCMP0067Variables.emplace_back(langPropVar);
+ }
+ if (!value.empty()) {
+ arguments.LangProps[langProp] = value;
+ }
+ }
+ }
+ }
+ }
if (!warnCMP0067Variables.empty()) {
std::ostringstream w;
@@ -841,17 +899,20 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
}
- cState.WriteProperties(fout, targetName);
- cxxState.WriteProperties(fout, targetName);
- cudaState.WriteProperties(fout, targetName);
- hipState.WriteProperties(fout, targetName);
- objcState.WriteProperties(fout, targetName);
- objcxxState.WriteProperties(fout, targetName);
+ for (auto const& p : arguments.LangProps) {
+ if (p.second.empty()) {
+ continue;
+ }
+ fprintf(fout, "set_property(TARGET %s PROPERTY %s %s)\n",
+ targetName.c_str(),
+ cmOutputConverter::EscapeForCMake(p.first).c_str(),
+ cmOutputConverter::EscapeForCMake(p.second).c_str());
+ }
- if (!linkOptions.empty()) {
+ if (!arguments.LinkOptions.empty()) {
std::vector<std::string> options;
- options.reserve(linkOptions.size());
- for (const auto& option : linkOptions) {
+ options.reserve(arguments.LinkOptions.size());
+ for (const auto& option : arguments.LinkOptions) {
options.emplace_back(cmOutputConverter::EscapeForCMake(option));
}
@@ -865,15 +926,18 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
}
}
- if (useOldLinkLibs) {
- fprintf(fout, "target_link_libraries(%s ${LINK_LIBRARIES})\n",
- targetName.c_str());
- } else {
+ if (arguments.LinkLibraries) {
+ std::string libsToLink = " ";
+ for (std::string const& i : *arguments.LinkLibraries) {
+ libsToLink += "\"" + cmTrimWhitespace(i) + "\" ";
+ }
fprintf(fout, "target_link_libraries(%s %s)\n", targetName.c_str(),
libsToLink.c_str());
+ } else {
+ fprintf(fout, "target_link_libraries(%s ${LINK_LIBRARIES})\n",
+ targetName.c_str());
}
fclose(fout);
- projectName = "CMAKE_TRY_COMPILE";
}
// Forward a set of variables to the inner project cache.
@@ -920,6 +984,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
vars.insert(kCMAKE_WARN_DEPRECATED);
vars.emplace("CMAKE_MSVC_RUNTIME_LIBRARY"_s);
vars.emplace("CMAKE_WATCOM_RUNTIME_LIBRARY"_s);
+ vars.emplace("CMAKE_MSVC_DEBUG_INFORMATION_FORMAT"_s);
if (cmValue varListStr = this->Makefile->GetDefinition(
kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) {
@@ -962,13 +1027,13 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES)) {
vars.erase(kCMAKE_OSX_ARCHITECTURES);
std::string flag = "-DCMAKE_OSX_ARCHITECTURES=" + *tcArchs;
- cmakeFlags.emplace_back(std::move(flag));
+ arguments.CMakeFlags.emplace_back(std::move(flag));
}
for (std::string const& var : vars) {
if (cmValue val = this->Makefile->GetDefinition(var)) {
std::string flag = "-D" + var + "=" + *val;
- cmakeFlags.emplace_back(std::move(flag));
+ arguments.CMakeFlags.emplace_back(std::move(flag));
}
}
}
@@ -978,7 +1043,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
for (std::string const& var : ghs_platform_vars) {
if (cmValue val = this->Makefile->GetDefinition(var)) {
std::string flag = "-D" + var + "=" + "'" + *val + "'";
- cmakeFlags.emplace_back(std::move(flag));
+ arguments.CMakeFlags.emplace_back(std::move(flag));
}
}
}
@@ -989,26 +1054,27 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
// actually do the try compile now that everything is setup
int res = this->Makefile->TryCompile(
sourceDirectory, this->BinaryDirectory, projectName, targetName,
- this->SrcFileSignature, cmake::NO_BUILD_PARALLEL_LEVEL, &cmakeFlags,
- output);
+ this->SrcFileSignature, cmake::NO_BUILD_PARALLEL_LEVEL,
+ &arguments.CMakeFlags, output);
if (erroroc) {
cmSystemTools::SetErrorOccurred();
}
// set the result var to the return value to indicate success or failure
- this->Makefile->AddCacheDefinition(argv[0], (res == 0 ? "TRUE" : "FALSE"),
- "Result of TRY_COMPILE",
- cmStateEnums::INTERNAL);
+ this->Makefile->AddCacheDefinition(
+ *arguments.CompileResultVariable, (res == 0 ? "TRUE" : "FALSE"),
+ "Result of TRY_COMPILE", cmStateEnums::INTERNAL);
- if (!outputVariable.empty()) {
- this->Makefile->AddDefinition(outputVariable, output);
+ if (arguments.OutputVariable) {
+ this->Makefile->AddDefinition(*arguments.OutputVariable, output);
}
if (this->SrcFileSignature) {
std::string copyFileErrorMessage;
- this->FindOutputFile(targetName, targetType);
+ this->FindOutputFile(targetName);
- if ((res == 0) && !copyFile.empty()) {
+ if ((res == 0) && arguments.CopyFileTo) {
+ std::string const& copyFile = *arguments.CopyFileTo;
if (this->OutputFile.empty() ||
!cmSystemTools::CopyFileAlways(this->OutputFile, copyFile)) {
std::ostringstream emsg;
@@ -1021,19 +1087,26 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
if (!this->FindErrorMessage.empty()) {
emsg << this->FindErrorMessage;
}
- if (copyFileError.empty()) {
+ if (!arguments.CopyFileError) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, emsg.str());
- return -1;
+ return false;
}
copyFileErrorMessage = emsg.str();
}
}
- if (!copyFileError.empty()) {
+ if (arguments.CopyFileError) {
+ std::string const& copyFileError = *arguments.CopyFileError;
this->Makefile->AddDefinition(copyFileError, copyFileErrorMessage);
}
}
- return res;
+ return res == 0;
+}
+
+bool cmCoreTryCompile::IsTemporary(std::string const& path)
+{
+ return ((path.find("CMakeTmp") != std::string::npos) ||
+ (path.find("CMakeScratch") != std::string::npos));
}
void cmCoreTryCompile::CleanupFiles(std::string const& binDir)
@@ -1042,11 +1115,11 @@ void cmCoreTryCompile::CleanupFiles(std::string const& binDir)
return;
}
- if (binDir.find("CMakeTmp") == std::string::npos) {
+ if (!IsTemporary(binDir)) {
cmSystemTools::Error(
"TRY_COMPILE attempt to remove -rf directory that does not contain "
- "CMakeTmp:" +
- binDir);
+ "CMakeTmp or CMakeScratch: \"" +
+ binDir + "\"");
return;
}
@@ -1092,64 +1165,74 @@ void cmCoreTryCompile::CleanupFiles(std::string const& binDir)
}
}
}
+
+ if (binDir.find("CMakeScratch") != std::string::npos) {
+ cmSystemTools::RemoveADirectory(binDir);
+ }
}
-void cmCoreTryCompile::FindOutputFile(const std::string& targetName,
- cmStateEnums::TargetType targetType)
+void cmCoreTryCompile::FindOutputFile(const std::string& targetName)
{
this->FindErrorMessage.clear();
this->OutputFile.clear();
std::string tmpOutputFile = "/";
- if (targetType == cmStateEnums::EXECUTABLE) {
- tmpOutputFile += targetName;
- tmpOutputFile +=
- this->Makefile->GetSafeDefinition("CMAKE_EXECUTABLE_SUFFIX");
- } else // if (targetType == cmStateEnums::STATIC_LIBRARY)
- {
- tmpOutputFile +=
- this->Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX");
- tmpOutputFile += targetName;
- tmpOutputFile +=
- this->Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX");
+ tmpOutputFile += targetName;
+
+ if (this->Makefile->GetGlobalGenerator()->IsMultiConfig()) {
+ tmpOutputFile += "_DEBUG";
+ }
+ tmpOutputFile += "_loc";
+
+ std::string command = cmStrCat(this->BinaryDirectory, tmpOutputFile);
+ if (!cmSystemTools::FileExists(command)) {
+ std::ostringstream emsg;
+ emsg << "Unable to find the recorded try_compile output location:\n";
+ emsg << cmStrCat(" ", command, "\n");
+ this->FindErrorMessage = emsg.str();
+ return;
}
- // a list of directories where to search for the compilation result
- // at first directly in the binary dir
- std::vector<std::string> searchDirs;
- searchDirs.emplace_back();
-
- cmValue config =
- this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
- // if a config was specified try that first
- if (cmNonempty(config)) {
- std::string tmp = cmStrCat('/', *config);
- searchDirs.emplace_back(std::move(tmp));
+ std::string outputFileLocation;
+ cmsys::ifstream ifs(command.c_str());
+ cmSystemTools::GetLineFromStream(ifs, outputFileLocation);
+ if (!cmSystemTools::FileExists(outputFileLocation)) {
+ std::ostringstream emsg;
+ emsg << "Recorded try_compile output location doesn't exist:\n";
+ emsg << cmStrCat(" ", outputFileLocation, "\n");
+ this->FindErrorMessage = emsg.str();
+ return;
}
- searchDirs.emplace_back("/Debug");
- // handle app-bundles (for targeting apple-platforms)
- std::string app = "/" + targetName + ".app";
- if (cmNonempty(config)) {
- std::string tmp = cmStrCat('/', *config, app);
- searchDirs.emplace_back(std::move(tmp));
+ this->OutputFile = cmSystemTools::CollapseFullPath(outputFileLocation);
+}
+
+std::string cmCoreTryCompile::WriteSource(std::string const& filename,
+ std::string const& content,
+ char const* command) const
+{
+ if (!cmSystemTools::GetFilenamePath(filename).empty()) {
+ const auto& msg =
+ cmStrCat(command, " given invalid filename \"", filename, "\"");
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
+ return {};
}
- std::string tmp = "/Debug" + app;
- searchDirs.emplace_back(std::move(tmp));
- searchDirs.emplace_back(std::move(app));
- searchDirs.emplace_back("/Development");
+ auto filepath = cmStrCat(this->BinaryDirectory, "/", filename);
+ cmsys::ofstream file{ filepath.c_str(), std::ios::out };
+ if (!file) {
+ const auto& msg =
+ cmStrCat(command, " failed to open \"", filename, "\" for writing");
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
+ return {};
+ }
- for (std::string const& sdir : searchDirs) {
- std::string command = cmStrCat(this->BinaryDirectory, sdir, tmpOutputFile);
- if (cmSystemTools::FileExists(command)) {
- this->OutputFile = cmSystemTools::CollapseFullPath(command);
- return;
- }
+ file << content;
+ if (!file) {
+ const auto& msg = cmStrCat(command, " failed to write \"", filename, "\"");
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
+ return {};
}
- std::ostringstream emsg;
- emsg << "Unable to find the executable at any of:\n";
- emsg << cmWrap(" " + this->BinaryDirectory, searchDirs, tmpOutputFile, "\n")
- << "\n";
- this->FindErrorMessage = emsg.str();
+ file.close();
+ return filepath;
}
diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h
index 594fd7f..3f4a4dc 100644
--- a/Source/cmCoreTryCompile.h
+++ b/Source/cmCoreTryCompile.h
@@ -4,28 +4,89 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <map>
#include <string>
#include <vector>
-#include "cmCommand.h"
+#include <cm/optional>
+
+#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmStateTypes.h"
+class cmMakefile;
+template <typename Iter>
+class cmRange;
+
/** \class cmCoreTryCompile
* \brief Base class for cmTryCompileCommand and cmTryRunCommand
*
* cmCoreTryCompile implements the functionality to build a program.
* It is the base class for cmTryCompileCommand and cmTryRunCommand.
*/
-class cmCoreTryCompile : public cmCommand
+class cmCoreTryCompile
{
public:
-protected:
+ cmCoreTryCompile(cmMakefile* mf)
+ : Makefile(mf)
+ {
+ }
+
+ struct Arguments : public ArgumentParser::ParseResult
+ {
+ cm::optional<std::string> CompileResultVariable;
+ cm::optional<std::string> BinaryDirectory;
+ cm::optional<std::string> SourceDirectoryOrFile;
+ cm::optional<std::string> ProjectName;
+ cm::optional<std::string> TargetName;
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> Sources;
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>>
+ SourceFromArg;
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>>
+ SourceFromVar;
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>>
+ SourceFromFile;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> CMakeFlags{
+ 1, "CMAKE_FLAGS"
+ }; // fake argv[0]
+ std::vector<std::string> CompileDefs;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>>
+ LinkLibraries;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> LinkOptions;
+ std::map<std::string, std::string> LangProps;
+ std::string CMakeInternal;
+ cm::optional<std::string> OutputVariable;
+ cm::optional<std::string> CopyFileTo;
+ cm::optional<std::string> CopyFileError;
+
+ // Argument for try_run only.
+ // Keep in sync with warnings in cmCoreTryCompile::ParseArgs.
+ cm::optional<std::string> CompileOutputVariable;
+ cm::optional<std::string> RunOutputVariable;
+ cm::optional<std::string> RunOutputStdOutVariable;
+ cm::optional<std::string> RunOutputStdErrVariable;
+ cm::optional<std::string> RunWorkingDirectory;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> RunArgs;
+ };
+
+ Arguments ParseArgs(cmRange<std::vector<std::string>::const_iterator> args,
+ bool isTryRun);
+
/**
- * This is the core code for try compile. It is here so that other
- * commands, such as TryRun can access the same logic without
- * duplication.
+ * This is the core code for try compile. It is here so that other commands,
+ * such as TryRun can access the same logic without duplication.
+ *
+ * This function requires at least two \p arguments and will crash if given
+ * fewer.
*/
- int TryCompileCode(std::vector<std::string> const& argv, bool isTryRun);
+ bool TryCompileCode(Arguments& arguments,
+ cmStateEnums::TargetType targetType);
+
+ /**
+ * Returns \c true if \p path resides within a CMake temporary directory,
+ * otherwise returns \c false.
+ */
+ static bool IsTemporary(std::string const& path);
/**
* This deletes all the files created by TryCompileCode.
@@ -39,11 +100,20 @@ protected:
TryCompileCode. The result is stored in OutputFile. If nothing is found,
the error message is stored in FindErrorMessage.
*/
- void FindOutputFile(const std::string& targetName,
- cmStateEnums::TargetType targetType);
+ void FindOutputFile(const std::string& targetName);
std::string BinaryDirectory;
std::string OutputFile;
std::string FindErrorMessage;
bool SrcFileSignature = false;
+ cmMakefile* Makefile;
+
+private:
+ std::string WriteSource(std::string const& name, std::string const& content,
+ char const* command) const;
+
+ Arguments ParseArgs(
+ const cmRange<std::vector<std::string>::const_iterator>& args,
+ const cmArgumentParser<Arguments>& parser,
+ std::vector<std::string>& unparsedArguments);
};
diff --git a/Source/cmCreateTestSourceList.cxx b/Source/cmCreateTestSourceList.cxx
index 2a52d1a..75c25e3 100644
--- a/Source/cmCreateTestSourceList.cxx
+++ b/Source/cmCreateTestSourceList.cxx
@@ -87,9 +87,7 @@ bool cmCreateTestSourceList(std::vector<std::string> const& args,
func_name = cmSystemTools::GetFilenameWithoutLastExtension(*i);
}
cmSystemTools::ConvertToUnixSlashes(func_name);
- std::replace(func_name.begin(), func_name.end(), ' ', '_');
- std::replace(func_name.begin(), func_name.end(), '/', '_');
- std::replace(func_name.begin(), func_name.end(), ':', '_');
+ func_name = cmSystemTools::MakeCidentifier(func_name);
bool already_declared =
std::find(tests_func_name.begin(), tests_func_name.end(), func_name) !=
tests_func_name.end();
diff --git a/Source/cmCurl.cxx b/Source/cmCurl.cxx
index 28ee24d..fd6aee1 100644
--- a/Source/cmCurl.cxx
+++ b/Source/cmCurl.cxx
@@ -34,10 +34,21 @@
std::string cmCurlSetCAInfo(::CURL* curl, const std::string& cafile)
{
std::string e;
+ std::string env_ca;
if (!cafile.empty()) {
::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_CAINFO, cafile.c_str());
check_curl_result(res, "Unable to set TLS/SSL Verify CAINFO: ");
}
+ /* Honor the user-configurable OpenSSL environment variables. */
+ else if (cmSystemTools::GetEnv("SSL_CERT_FILE", env_ca) &&
+ cmSystemTools::FileExists(env_ca, true)) {
+ ::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_CAINFO, env_ca.c_str());
+ check_curl_result(res, "Unable to set TLS/SSL Verify CAINFO: ");
+ } else if (cmSystemTools::GetEnv("SSL_CERT_DIR", env_ca) &&
+ cmSystemTools::FileIsDirectory(env_ca)) {
+ ::CURLcode res = ::curl_easy_setopt(curl, CURLOPT_CAPATH, env_ca.c_str());
+ check_curl_result(res, "Unable to set TLS/SSL Verify CAINFO: ");
+ }
#ifdef CMAKE_FIND_CAFILE
# define CMAKE_CAFILE_FEDORA "/etc/pki/tls/certs/ca-bundle.crt"
else if (cmSystemTools::FileExists(CMAKE_CAFILE_FEDORA, true)) {
diff --git a/Source/cmCxxModuleMapper.cxx b/Source/cmCxxModuleMapper.cxx
index 94ad721..84691c9 100644
--- a/Source/cmCxxModuleMapper.cxx
+++ b/Source/cmCxxModuleMapper.cxx
@@ -3,10 +3,19 @@
#include "cmCxxModuleMapper.h"
#include <cassert>
+#include <cstddef>
+#include <set>
#include <sstream>
+#include <string>
+#include <utility>
#include <vector>
+#include <cm/string_view>
+#include <cmext/string_view>
+
#include "cmScanDepFormat.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
cm::optional<std::string> CxxModuleLocations::BmiGeneratorPathForModule(
std::string const& logical_name) const
@@ -47,6 +56,122 @@ std::string CxxModuleMapContentGcc(CxxModuleLocations const& loc,
return mm.str();
}
+
+std::string CxxModuleMapContentMsvc(CxxModuleLocations const& loc,
+ cmScanDepInfo const& obj,
+ CxxModuleUsage const& usages)
+{
+ std::stringstream mm;
+
+ // A response file of `-reference NAME=PATH` arguments.
+
+ // MSVC's command line only supports a single output. If more than one is
+ // expected, we cannot make a useful module map file.
+ if (obj.Provides.size() > 1) {
+ return {};
+ }
+
+ auto flag_for_method = [](LookupMethod method) -> cm::static_string_view {
+ switch (method) {
+ case LookupMethod::ByName:
+ return "-reference"_s;
+ case LookupMethod::IncludeAngle:
+ return "-headerUnit:angle"_s;
+ case LookupMethod::IncludeQuote:
+ return "-headerUnit:quote"_s;
+ }
+ assert(false && "unsupported lookup method");
+ return ""_s;
+ };
+
+ for (auto const& p : obj.Provides) {
+ if (p.IsInterface) {
+ mm << "-interface\n";
+ } else {
+ mm << "-internalPartition\n";
+ }
+
+ if (auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName)) {
+ mm << "-ifcOutput " << *bmi_loc << '\n';
+ }
+ }
+
+ std::set<std::string> transitive_usage_directs;
+ std::set<std::string> transitive_usage_names;
+
+ for (auto const& r : obj.Requires) {
+ if (auto bmi_loc = loc.BmiGeneratorPathForModule(r.LogicalName)) {
+ auto flag = flag_for_method(r.Method);
+
+ mm << flag << ' ' << r.LogicalName << '=' << *bmi_loc << "\n";
+ transitive_usage_directs.insert(r.LogicalName);
+
+ // Insert transitive usages.
+ auto transitive_usages = usages.Usage.find(r.LogicalName);
+ if (transitive_usages != usages.Usage.end()) {
+ transitive_usage_names.insert(transitive_usages->second.begin(),
+ transitive_usages->second.end());
+ }
+ }
+ }
+
+ for (auto const& transitive_name : transitive_usage_names) {
+ if (transitive_usage_directs.count(transitive_name)) {
+ continue;
+ }
+
+ auto module_ref = usages.Reference.find(transitive_name);
+ if (module_ref != usages.Reference.end()) {
+ auto flag = flag_for_method(module_ref->second.Method);
+ mm << flag << ' ' << transitive_name << '=' << module_ref->second.Path
+ << "\n";
+ }
+ }
+
+ return mm.str();
+}
+}
+
+bool CxxModuleUsage::AddReference(std::string const& logical,
+ std::string const& loc, LookupMethod method)
+{
+ auto r = this->Reference.find(logical);
+ if (r != this->Reference.end()) {
+ auto& ref = r->second;
+
+ if (ref.Path == loc && ref.Method == method) {
+ return true;
+ }
+
+ auto method_name = [](LookupMethod m) -> cm::static_string_view {
+ switch (m) {
+ case LookupMethod::ByName:
+ return "by-name"_s;
+ case LookupMethod::IncludeAngle:
+ return "include-angle"_s;
+ case LookupMethod::IncludeQuote:
+ return "include-quote"_s;
+ }
+ assert(false && "unsupported lookup method");
+ return ""_s;
+ };
+
+ cmSystemTools::Error(cmStrCat("Disagreement of the location of the '",
+ logical,
+ "' module. "
+ "Location A: '",
+ ref.Path, "' via ", method_name(ref.Method),
+ "; "
+ "Location B: '",
+ loc, "' via ", method_name(method), "."));
+ return false;
+ }
+
+ auto& ref = this->Reference[logical];
+ ref.Path = loc;
+ ref.Method = method;
+
+ return true;
}
cm::static_string_view CxxModuleMapExtension(
@@ -56,19 +181,126 @@ cm::static_string_view CxxModuleMapExtension(
switch (*format) {
case CxxModuleMapFormat::Gcc:
return ".gcm"_s;
+ case CxxModuleMapFormat::Msvc:
+ return ".ifc"_s;
}
}
return ".bmi"_s;
}
+std::set<std::string> CxxModuleUsageSeed(
+ CxxModuleLocations const& loc, std::vector<cmScanDepInfo> const& objects,
+ CxxModuleUsage& usages)
+{
+ // Track inner usages to populate usages from internal bits.
+ //
+ // This is a map of modules that required some other module that was not
+ // found to those that were not found.
+ std::map<std::string, std::set<std::string>> internal_usages;
+ std::set<std::string> unresolved;
+
+ for (cmScanDepInfo const& object : objects) {
+ // Add references for each of the provided modules.
+ for (auto const& p : object.Provides) {
+ if (auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName)) {
+ // XXX(cxx-modules): How to support header units?
+ usages.AddReference(p.LogicalName, loc.PathForGenerator(*bmi_loc),
+ LookupMethod::ByName);
+ }
+ }
+
+ // For each requires, pull in what is required.
+ for (auto const& r : object.Requires) {
+ // Find transitive usages.
+ auto transitive_usages = usages.Usage.find(r.LogicalName);
+ // Find the required name in the current target.
+ auto bmi_loc = loc.BmiGeneratorPathForModule(r.LogicalName);
+
+ for (auto const& p : object.Provides) {
+ auto& this_usages = usages.Usage[p.LogicalName];
+
+ // Add the direct usage.
+ this_usages.insert(r.LogicalName);
+
+ // Add the transitive usage.
+ if (transitive_usages != usages.Usage.end()) {
+ this_usages.insert(transitive_usages->second.begin(),
+ transitive_usages->second.end());
+ } else if (bmi_loc) {
+ // Mark that we need to update transitive usages later.
+ internal_usages[p.LogicalName].insert(r.LogicalName);
+ }
+ }
+
+ if (bmi_loc) {
+ usages.AddReference(r.LogicalName, loc.PathForGenerator(*bmi_loc),
+ r.Method);
+ }
+ }
+ }
+
+ // While we have internal usages to manage.
+ while (!internal_usages.empty()) {
+ size_t starting_size = internal_usages.size();
+
+ // For each internal usage.
+ for (auto usage = internal_usages.begin(); usage != internal_usages.end();
+ /* see end of loop */) {
+ auto& this_usages = usages.Usage[usage->first];
+
+ for (auto use = usage->second.begin(); use != usage->second.end();
+ /* see end of loop */) {
+ // Check if this required module uses other internal modules; defer
+ // if so.
+ if (internal_usages.count(*use)) {
+ // Advance the iterator.
+ ++use;
+ continue;
+ }
+
+ auto transitive_usages = usages.Usage.find(*use);
+ if (transitive_usages != usages.Usage.end()) {
+ this_usages.insert(transitive_usages->second.begin(),
+ transitive_usages->second.end());
+ }
+
+ // Remove the entry and advance the iterator.
+ use = usage->second.erase(use);
+ }
+
+ // Erase the entry if it doesn't have any remaining usages.
+ if (usage->second.empty()) {
+ usage = internal_usages.erase(usage);
+ } else {
+ ++usage;
+ }
+ }
+
+ // Check that at least one usage was resolved.
+ if (starting_size == internal_usages.size()) {
+ // Nothing could be resolved this loop; we have a cycle, so record the
+ // cycle and exit.
+ for (auto const& usage : internal_usages) {
+ unresolved.insert(usage.first);
+ }
+ break;
+ }
+ }
+
+ return unresolved;
+}
+
std::string CxxModuleMapContent(CxxModuleMapFormat format,
CxxModuleLocations const& loc,
- cmScanDepInfo const& obj)
+ cmScanDepInfo const& obj,
+ CxxModuleUsage const& usages)
{
switch (format) {
case CxxModuleMapFormat::Gcc:
return CxxModuleMapContentGcc(loc, obj);
+ case CxxModuleMapFormat::Msvc:
+ return CxxModuleMapContentMsvc(loc, obj, usages);
}
assert(false);
diff --git a/Source/cmCxxModuleMapper.h b/Source/cmCxxModuleMapper.h
index 99384c9..8526a07 100644
--- a/Source/cmCxxModuleMapper.h
+++ b/Source/cmCxxModuleMapper.h
@@ -5,16 +5,20 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <functional>
+#include <map>
+#include <set>
#include <string>
+#include <vector>
#include <cm/optional>
#include <cmext/string_view>
-struct cmScanDepInfo;
+#include "cmScanDepFormat.h"
enum class CxxModuleMapFormat
{
Gcc,
+ Msvc,
};
struct CxxModuleLocations
@@ -37,12 +41,45 @@ struct CxxModuleLocations
std::string const& logical_name) const;
};
+struct CxxModuleReference
+{
+ // The path to the module file used.
+ std::string Path;
+ // How the module was looked up.
+ LookupMethod Method;
+};
+
+struct CxxModuleUsage
+{
+ // The usage requirements for this object.
+ std::map<std::string, std::set<std::string>> Usage;
+
+ // The references for this object.
+ std::map<std::string, CxxModuleReference> Reference;
+
+ // Add a reference to a module.
+ //
+ // Returns `true` if it matches how it was found previously, `false` if it
+ // conflicts.
+ bool AddReference(std::string const& logical, std::string const& loc,
+ LookupMethod method);
+};
+
// Return the extension to use for a given modulemap format.
cm::static_string_view CxxModuleMapExtension(
cm::optional<CxxModuleMapFormat> format);
+// Fill in module usage information for internal usages.
+//
+// Returns the set of unresolved module usage requirements (these form an
+// import cycle).
+std::set<std::string> CxxModuleUsageSeed(
+ CxxModuleLocations const& loc, std::vector<cmScanDepInfo> const& objects,
+ CxxModuleUsage& usages);
+
// Return the contents of the module map in the given format for the
// object file.
std::string CxxModuleMapContent(CxxModuleMapFormat format,
CxxModuleLocations const& loc,
- cmScanDepInfo const& obj);
+ cmScanDepInfo const& obj,
+ CxxModuleUsage const& usages);
diff --git a/Source/cmDefinePropertyCommand.cxx b/Source/cmDefinePropertyCommand.cxx
index faefcb8..31ee665 100644
--- a/Source/cmDefinePropertyCommand.cxx
+++ b/Source/cmDefinePropertyCommand.cxx
@@ -8,6 +8,7 @@
#include <cmext/string_view>
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmProperty.h"
@@ -51,8 +52,8 @@ bool cmDefinePropertyCommand(std::vector<std::string> const& args,
// Parse remaining arguments.
bool inherited = false;
std::string PropertyName;
- std::vector<std::string> BriefDocs;
- std::vector<std::string> FullDocs;
+ ArgumentParser::NonEmpty<std::vector<std::string>> BriefDocs;
+ ArgumentParser::NonEmpty<std::vector<std::string>> FullDocs;
std::string initializeFromVariable;
cmArgumentParser<void> parser;
diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx
index 3619ade..d466a12 100644
--- a/Source/cmDocumentation.cxx
+++ b/Source/cmDocumentation.cxx
@@ -17,30 +17,32 @@
#include "cmVersion.h"
static const char* cmDocumentationStandardOptions[][2] = {
- { "--help,-help,-usage,-h,-H,/?", "Print usage information and exit." },
- { "--version,-version,/V [<f>]", "Print version number and exit." },
- { "--help-full [<f>]", "Print all help manuals and exit." },
- { "--help-manual <man> [<f>]", "Print one help manual and exit." },
- { "--help-manual-list [<f>]", "List help manuals available and exit." },
- { "--help-command <cmd> [<f>]", "Print help for one command and exit." },
- { "--help-command-list [<f>]",
+ { "-h,-H,--help,-help,-usage,/?", "Print usage information and exit." },
+ { "--version,-version,/V [<file>]", "Print version number and exit." },
+ { "--help-full [<file>]", "Print all help manuals and exit." },
+ { "--help-manual <man> [<file>]", "Print one help manual and exit." },
+ { "--help-manual-list [<file>]", "List help manuals available and exit." },
+ { "--help-command <cmd> [<file>]", "Print help for one command and exit." },
+ { "--help-command-list [<file>]",
"List commands with help available and exit." },
- { "--help-commands [<f>]", "Print cmake-commands manual and exit." },
- { "--help-module <mod> [<f>]", "Print help for one module and exit." },
- { "--help-module-list [<f>]", "List modules with help available and exit." },
- { "--help-modules [<f>]", "Print cmake-modules manual and exit." },
- { "--help-policy <cmp> [<f>]", "Print help for one policy and exit." },
- { "--help-policy-list [<f>]",
+ { "--help-commands [<file>]", "Print cmake-commands manual and exit." },
+ { "--help-module <mod> [<file>]", "Print help for one module and exit." },
+ { "--help-module-list [<file>]",
+ "List modules with help available and exit." },
+ { "--help-modules [<file>]", "Print cmake-modules manual and exit." },
+ { "--help-policy <cmp> [<file>]", "Print help for one policy and exit." },
+ { "--help-policy-list [<file>]",
"List policies with help available and exit." },
- { "--help-policies [<f>]", "Print cmake-policies manual and exit." },
- { "--help-property <prop> [<f>]", "Print help for one property and exit." },
- { "--help-property-list [<f>]",
+ { "--help-policies [<file>]", "Print cmake-policies manual and exit." },
+ { "--help-property <prop> [<file>]",
+ "Print help for one property and exit." },
+ { "--help-property-list [<file>]",
"List properties with help available and exit." },
- { "--help-properties [<f>]", "Print cmake-properties manual and exit." },
- { "--help-variable var [<f>]", "Print help for one variable and exit." },
- { "--help-variable-list [<f>]",
+ { "--help-properties [<file>]", "Print cmake-properties manual and exit." },
+ { "--help-variable var [<file>]", "Print help for one variable and exit." },
+ { "--help-variable-list [<file>]",
"List variables with help available and exit." },
- { "--help-variables [<f>]", "Print cmake-variables manual and exit." },
+ { "--help-variables [<file>]", "Print cmake-variables manual and exit." },
{ nullptr, nullptr }
};
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index 222ea80..7fbd826 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -47,7 +47,7 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
return false;
}
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
std::vector<std::vector<std::string>> Commands;
std::string OutputVariable;
@@ -95,14 +95,10 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
.Bind("COMMAND_ERROR_IS_FATAL"_s, &Arguments::CommandErrorIsFatal);
std::vector<std::string> unparsedArguments;
- std::vector<std::string> keywordsMissingValue;
- Arguments const arguments =
- parser.Parse(args, &unparsedArguments, &keywordsMissingValue);
+ Arguments const arguments = parser.Parse(args, &unparsedArguments);
- if (!keywordsMissingValue.empty()) {
- status.SetError(" called with no value for " +
- keywordsMissingValue.front() + ".");
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (!unparsedArguments.empty()) {
status.SetError(" given unknown argument \"" + unparsedArguments.front() +
diff --git a/Source/cmExecutionStatus.h b/Source/cmExecutionStatus.h
index 0feaedf..ced3548 100644
--- a/Source/cmExecutionStatus.h
+++ b/Source/cmExecutionStatus.h
@@ -5,6 +5,7 @@
#include <cmConfigure.h> // IWYU pragma: keep
#include <string>
+#include <vector>
class cmMakefile;
@@ -27,8 +28,21 @@ public:
void SetError(std::string const& e) { this->Error = e; }
std::string const& GetError() const { return this->Error; }
- void SetReturnInvoked() { this->ReturnInvoked = true; }
+ void SetReturnInvoked()
+ {
+ this->Variables.clear();
+ this->ReturnInvoked = true;
+ }
+ void SetReturnInvoked(std::vector<std::string> variables)
+ {
+ this->Variables = std::move(variables);
+ this->ReturnInvoked = true;
+ }
bool GetReturnInvoked() const { return this->ReturnInvoked; }
+ const std::vector<std::string>& GetReturnVariables() const
+ {
+ return this->Variables;
+ }
void SetBreakInvoked() { this->BreakInvoked = true; }
bool GetBreakInvoked() const { return this->BreakInvoked; }
@@ -46,4 +60,5 @@ private:
bool BreakInvoked = false;
bool ContinueInvoked = false;
bool NestedError = false;
+ std::vector<std::string> Variables;
};
diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx
index e815d0e..922b53f 100644
--- a/Source/cmExperimental.cxx
+++ b/Source/cmExperimental.cxx
@@ -27,7 +27,7 @@ struct FeatureData
bool Warned;
} LookupTable[] = {
// CxxModuleCMakeApi
- { "17be90bd-a850-44e0-be50-448de847d652",
+ { "3c375311-a3c9-4396-a187-3227ef642046",
"CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API",
"CMake's C++ module support is experimental. It is meant only for "
"experimentation and feedback to CMake developers.",
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index af33ada..ed199ea 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -15,6 +15,7 @@
#include "cmExportSet.h"
#include "cmFileSet.h"
+#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
@@ -25,6 +26,7 @@
#include "cmPolicies.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmTargetExport.h"
#include "cmValue.h"
@@ -141,11 +143,18 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
this->GenerateTargetFileSets(gte, os);
}
+ this->GenerateCxxModuleInformation(os);
+
// Generate import file content for each configuration.
for (std::string const& c : this->Configurations) {
this->GenerateImportConfig(os, c);
}
+ // Generate import file content for each configuration.
+ for (std::string const& c : this->Configurations) {
+ this->GenerateImportCxxModuleConfigTargetInclusion(c);
+ }
+
this->GenerateMissingTargetsCheckCode(os);
return true;
@@ -479,3 +488,60 @@ std::string cmExportBuildFileGenerator::GetFileSetFiles(cmGeneratorTarget* gte,
return cmJoin(resultVector, " ");
}
+
+std::string cmExportBuildFileGenerator::GetCxxModulesDirectory() const
+{
+ return this->CxxModulesDirectory;
+}
+
+void cmExportBuildFileGenerator::GenerateCxxModuleConfigInformation(
+ std::ostream& os) const
+{
+ const char* opt = "";
+ if (this->Configurations.size() > 1) {
+ // With more than one configuration, each individual file is optional.
+ opt = " OPTIONAL";
+ }
+
+ // Generate import file content for each configuration.
+ for (std::string c : this->Configurations) {
+ if (c.empty()) {
+ c = "noconfig";
+ }
+ os << "include(\"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << c << ".cmake\""
+ << opt << ")\n";
+ }
+}
+
+bool cmExportBuildFileGenerator::GenerateImportCxxModuleConfigTargetInclusion(
+ std::string config) const
+{
+ auto cxx_modules_dirname = this->GetCxxModulesDirectory();
+ if (cxx_modules_dirname.empty()) {
+ return true;
+ }
+
+ if (config.empty()) {
+ config = "noconfig";
+ }
+
+ std::string fileName = cmStrCat(this->FileDir, '/', cxx_modules_dirname,
+ "/cxx-modules-", config, ".cmake");
+
+ cmGeneratedFileStream os(fileName, true);
+ if (!os) {
+ std::string se = cmSystemTools::GetLastSystemError();
+ std::ostringstream e;
+ e << "cannot write to file \"" << fileName << "\": " << se;
+ cmSystemTools::Error(e.str());
+ return false;
+ }
+ os.SetCopyIfDifferent(true);
+
+ for (auto const* tgt : this->ExportedTargets) {
+ os << "include(\"${CMAKE_CURRENT_LIST_DIR}/target-" << tgt->GetExportName()
+ << '-' << config << ".cmake\")\n";
+ }
+
+ return true;
+}
diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h
index 5681e8f..4636196 100644
--- a/Source/cmExportBuildFileGenerator.h
+++ b/Source/cmExportBuildFileGenerator.h
@@ -47,6 +47,16 @@ public:
}
void SetExportSet(cmExportSet*);
+ /** Set the name of the C++ module directory. */
+ void SetCxxModuleDirectory(std::string cxx_module_dir)
+ {
+ this->CxxModulesDirectory = std::move(cxx_module_dir);
+ }
+ const std::string& GetCxxModuleDirectory() const
+ {
+ return this->CxxModulesDirectory;
+ }
+
/** Set whether to append generated code to the output file. */
void SetAppendMode(bool append) { this->AppendMode = append; }
@@ -81,6 +91,10 @@ protected:
std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet,
cmTargetExport* te) override;
+ std::string GetCxxModulesDirectory() const override;
+ void GenerateCxxModuleConfigInformation(std::ostream&) const override;
+ bool GenerateImportCxxModuleConfigTargetInclusion(std::string) const;
+
std::pair<std::vector<std::string>, std::string> FindBuildExportInfo(
cmGlobalGenerator* gg, const std::string& name);
@@ -88,4 +102,6 @@ protected:
cmExportSet* ExportSet;
std::vector<cmGeneratorTarget*> Exports;
cmLocalGenerator* LG;
+ // The directory for C++ module information.
+ std::string CxxModulesDirectory;
};
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
index 63440a3..a58f2b7 100644
--- a/Source/cmExportCommand.cxx
+++ b/Source/cmExportCommand.cxx
@@ -7,13 +7,15 @@
#include <utility>
#include <cm/memory>
-#include <cmext/algorithm>
+#include <cm/optional>
#include <cmext/string_view>
#include "cmsys/RegularExpression.hxx"
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmExecutionStatus.h"
+#include "cmExperimental.h"
#include "cmExportBuildAndroidMKGenerator.h"
#include "cmExportBuildFileGenerator.h"
#include "cmExportSet.h"
@@ -57,10 +59,11 @@ bool cmExportCommand(std::vector<std::string> const& args,
struct Arguments
{
std::string ExportSetName;
- std::vector<std::string> Targets;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Targets;
std::string Namespace;
std::string Filename;
std::string AndroidMKFile;
+ std::string CxxModulesDirectory;
bool Append = false;
bool ExportOld = false;
};
@@ -69,6 +72,12 @@ bool cmExportCommand(std::vector<std::string> const& args,
.Bind("NAMESPACE"_s, &Arguments::Namespace)
.Bind("FILE"_s, &Arguments::Filename);
+ bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled(
+ status.GetMakefile(), cmExperimental::Feature::CxxModuleCMakeApi);
+ if (supportCxx20FileSetTypes) {
+ parser.Bind("CXX_MODULES_DIRECTORY"_s, &Arguments::CxxModulesDirectory);
+ }
+
if (args[0] == "EXPORT") {
parser.Bind("EXPORT"_s, &Arguments::ExportSetName);
} else {
@@ -79,9 +88,7 @@ bool cmExportCommand(std::vector<std::string> const& args,
}
std::vector<std::string> unknownArgs;
- std::vector<std::string> keywordsMissingValue;
- Arguments const arguments =
- parser.Parse(args, &unknownArgs, &keywordsMissingValue);
+ Arguments const arguments = parser.Parse(args, &unknownArgs);
if (!unknownArgs.empty()) {
status.SetError("Unknown argument: \"" + unknownArgs.front() + "\".");
@@ -145,9 +152,8 @@ bool cmExportCommand(std::vector<std::string> const& args,
return false;
}
exportSet = &it->second;
- } else if (!arguments.Targets.empty() ||
- cm::contains(keywordsMissingValue, "TARGETS")) {
- for (std::string const& currentTarget : arguments.Targets) {
+ } else if (arguments.Targets) {
+ for (std::string const& currentTarget : *arguments.Targets) {
if (mf.IsAlias(currentTarget)) {
std::ostringstream e;
e << "given ALIAS target \"" << currentTarget
@@ -214,6 +220,7 @@ bool cmExportCommand(std::vector<std::string> const& args,
}
ebfg->SetExportFile(fname.c_str());
ebfg->SetNamespace(arguments.Namespace);
+ ebfg->SetCxxModuleDirectory(arguments.CxxModulesDirectory);
ebfg->SetAppendMode(arguments.Append);
if (exportSet != nullptr) {
ebfg->SetExportSet(exportSet);
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 9837269..50bc78c 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -843,9 +843,16 @@ void cmExportFileGenerator::SetImportDetailProperties(
suffix, target, "IMPORTED_LINK_INTERFACE_LANGUAGES", iface->Languages,
properties, ImportLinkPropertyTargetNames::No);
+ // Export IMPORTED_LINK_DEPENDENT_LIBRARIES to help consuming linkers
+ // find private dependencies of shared libraries.
+ std::size_t oldMissingTargetsSize = this->MissingTargets.size();
this->SetImportLinkProperty(
suffix, target, "IMPORTED_LINK_DEPENDENT_LIBRARIES", iface->SharedDeps,
properties, ImportLinkPropertyTargetNames::Yes);
+ // Avoid enforcing shared library private dependencies as public package
+ // dependencies by ignoring missing targets added for them.
+ this->MissingTargets.resize(oldMissingTargetsSize);
+
if (iface->Multiplicity > 0) {
std::string prop =
cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix);
@@ -1305,3 +1312,28 @@ void cmExportFileGenerator::GenerateTargetFileSets(cmGeneratorTarget* gte,
os << " )\nendif()\n\n";
}
}
+
+void cmExportFileGenerator::GenerateCxxModuleInformation(std::ostream& os)
+{
+ auto const cxx_module_dirname = this->GetCxxModulesDirectory();
+ if (cxx_module_dirname.empty()) {
+ return;
+ }
+
+ // Write the include.
+ os << "# Include C++ module properties\n"
+ << "include(\"${CMAKE_CURRENT_LIST_DIR}/" << cxx_module_dirname
+ << "/cxx-modules.cmake\")\n\n";
+
+ // Get the path to the file we're going to write.
+ std::string path = this->MainImportFile;
+ path = cmSystemTools::GetFilenamePath(path);
+ auto trampoline_path =
+ cmStrCat(path, '/', cxx_module_dirname, "/cxx-modules.cmake");
+
+ // Include all configuration-specific include files.
+ cmGeneratedFileStream ap(trampoline_path, true);
+ ap.SetCopyIfDifferent(true);
+
+ this->GenerateCxxModuleConfigInformation(ap);
+}
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
index d27a555..fdda878 100644
--- a/Source/cmExportFileGenerator.h
+++ b/Source/cmExportFileGenerator.h
@@ -182,6 +182,8 @@ protected:
void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os,
cmTargetExport* te = nullptr);
+ void GenerateCxxModuleInformation(std::ostream& os);
+
virtual std::string GetFileSetDirectories(cmGeneratorTarget* gte,
cmFileSet* fileSet,
cmTargetExport* te) = 0;
@@ -226,4 +228,7 @@ private:
virtual std::string InstallNameDir(cmGeneratorTarget const* target,
const std::string& config) = 0;
+
+ virtual std::string GetCxxModulesDirectory() const = 0;
+ virtual void GenerateCxxModuleConfigInformation(std::ostream& os) const = 0;
};
diff --git a/Source/cmExportInstallAndroidMKGenerator.cxx b/Source/cmExportInstallAndroidMKGenerator.cxx
index 4e4f8a1..d53254d 100644
--- a/Source/cmExportInstallAndroidMKGenerator.cxx
+++ b/Source/cmExportInstallAndroidMKGenerator.cxx
@@ -35,8 +35,7 @@ void cmExportInstallAndroidMKGenerator::GenerateImportHeaderCode(
for (size_t n = 0; n < numDotDot; n++) {
path += "/..";
}
- os << "_IMPORT_PREFIX := "
- << "$(LOCAL_PATH)" << path << "\n\n";
+ os << "_IMPORT_PREFIX := $(LOCAL_PATH)" << path << "\n\n";
for (std::unique_ptr<cmTargetExport> const& te :
this->IEGen->GetExportSet()->GetTargetExports()) {
// Collect import properties for this target.
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index 3a06769..195737b 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -166,10 +166,20 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
this->LoadConfigFiles(os);
+ bool result = true;
+
+ this->GenerateCxxModuleInformation(os);
+ if (requiresConfigFiles) {
+ for (std::string const& c : this->Configurations) {
+ if (!this->GenerateImportCxxModuleConfigTargetInclusion(c)) {
+ result = false;
+ }
+ }
+ }
+
this->CleanupTemporaryVariables(os);
this->GenerateImportedFileCheckLoop(os);
- bool result = true;
// Generate an import file for each configuration.
// Don't do this if we only export INTERFACE_LIBRARY targets.
if (requiresConfigFiles) {
@@ -426,7 +436,10 @@ void cmExportInstallFileGenerator::SetImportLocationProperty(
// Append the installed file name.
if (target->IsAppBundleOnApple()) {
value += cmInstallTargetGenerator::GetInstallFilename(target, config);
- value += ".app/Contents/MacOS/";
+ value += ".app/";
+ if (!target->Makefile->PlatformIsAppleEmbedded()) {
+ value += "Contents/MacOS/";
+ }
value += cmInstallTargetGenerator::GetInstallFilename(target, config);
} else {
value += cmInstallTargetGenerator::GetInstallFilename(
@@ -669,3 +682,65 @@ std::string cmExportInstallFileGenerator::GetFileSetFiles(
return cmJoin(resultVector, " ");
}
+
+std::string cmExportInstallFileGenerator::GetCxxModulesDirectory() const
+{
+ return IEGen->GetCxxModuleDirectory();
+}
+
+void cmExportInstallFileGenerator::GenerateCxxModuleConfigInformation(
+ std::ostream& os) const
+{
+ // Now load per-configuration properties for them.
+ /* clang-format off */
+ os << "# Load information for each installed configuration.\n"
+ "file(GLOB _cmake_cxx_module_includes \"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-*.cmake\")\n"
+ "foreach(_cmake_cxx_module_include IN LISTS _cmake_cxx_module_includes)\n"
+ " include(\"${_cmake_cxx_module_include}\")\n"
+ "endforeach()\n"
+ "unset(_cmake_cxx_module_include)\n"
+ "unset(_cmake_cxx_module_includes)\n";
+ /* clang-format on */
+}
+
+bool cmExportInstallFileGenerator::
+ GenerateImportCxxModuleConfigTargetInclusion(std::string const& config)
+{
+ auto cxx_modules_dirname = this->GetCxxModulesDirectory();
+ if (cxx_modules_dirname.empty()) {
+ return true;
+ }
+
+ std::string filename_config = config;
+ if (filename_config.empty()) {
+ filename_config = "noconfig";
+ }
+
+ std::string const dest =
+ cmStrCat(this->FileDir, '/', cxx_modules_dirname, '/');
+ std::string fileName =
+ cmStrCat(dest, "cxx-modules-", filename_config, ".cmake");
+
+ cmGeneratedFileStream os(fileName, true);
+ if (!os) {
+ std::string se = cmSystemTools::GetLastSystemError();
+ std::ostringstream e;
+ e << "cannot write to file \"" << fileName << "\": " << se;
+ cmSystemTools::Error(e.str());
+ return false;
+ }
+ os.SetCopyIfDifferent(true);
+
+ // Record this per-config import file.
+ this->ConfigCxxModuleFiles[config] = fileName;
+
+ auto& prop_files = this->ConfigCxxModuleTargetFiles[config];
+ for (auto const* tgt : this->ExportedTargets) {
+ auto prop_filename = cmStrCat("target-", tgt->GetExportName(), '-',
+ filename_config, ".cmake");
+ prop_files.emplace_back(cmStrCat(dest, prop_filename));
+ os << "include(\"${CMAKE_CURRENT_LIST_DIR}/" << prop_filename << "\")\n";
+ }
+
+ return true;
+}
diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h
index 86fb505..e073a31 100644
--- a/Source/cmExportInstallFileGenerator.h
+++ b/Source/cmExportInstallFileGenerator.h
@@ -50,6 +50,23 @@ public:
return this->ConfigImportFiles;
}
+ /** Get the per-config C++ module file generated for each configuration.
+ This maps from the configuration name to the file temporary location
+ for installation. */
+ std::map<std::string, std::string> const& GetConfigCxxModuleFiles()
+ {
+ return this->ConfigCxxModuleFiles;
+ }
+
+ /** Get the per-config C++ module file generated for each configuration.
+ This maps from the configuration name to the file temporary location
+ for installation for each target in the export set. */
+ std::map<std::string, std::vector<std::string>> const&
+ GetConfigCxxModuleTargetFiles()
+ {
+ return this->ConfigCxxModuleTargetFiles;
+ }
+
/** Compute the globbing expression used to load per-config import
files from the main file. */
std::string GetConfigImportFileGlob();
@@ -100,8 +117,16 @@ protected:
std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet,
cmTargetExport* te) override;
+ std::string GetCxxModulesDirectory() const override;
+ void GenerateCxxModuleConfigInformation(std::ostream&) const override;
+ bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&);
+
cmInstallExportGenerator* IEGen;
// The import file generated for each configuration.
std::map<std::string, std::string> ConfigImportFiles;
+ // The C++ module property file generated for each configuration.
+ std::map<std::string, std::string> ConfigCxxModuleFiles;
+ // The C++ module property target files generated for each configuration.
+ std::map<std::string, std::vector<std::string>> ConfigCxxModuleTargetFiles;
};
diff --git a/Source/cmExportSet.cxx b/Source/cmExportSet.cxx
index a20aa9a..3d4ef0a 100644
--- a/Source/cmExportSet.cxx
+++ b/Source/cmExportSet.cxx
@@ -2,10 +2,15 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmExportSet.h"
+#include <algorithm>
#include <tuple>
#include <utility>
+#include "cmGeneratorTarget.h"
#include "cmLocalGenerator.h"
+#include "cmMessageType.h"
+#include "cmStringAlgorithms.h"
+#include "cmTarget.h"
#include "cmTargetExport.h"
cmExportSet::cmExportSet(std::string name)
@@ -15,11 +20,35 @@ cmExportSet::cmExportSet(std::string name)
cmExportSet::~cmExportSet() = default;
-void cmExportSet::Compute(cmLocalGenerator* lg)
+bool cmExportSet::Compute(cmLocalGenerator* lg)
{
for (std::unique_ptr<cmTargetExport>& tgtExport : this->TargetExports) {
tgtExport->Target = lg->FindGeneratorTargetToUse(tgtExport->TargetName);
+
+ auto const interfaceFileSets =
+ tgtExport->Target->Target->GetAllInterfaceFileSets();
+ auto const fileSetInTargetExport =
+ [&tgtExport, lg](const std::string& fileSetName) -> bool {
+ auto* fileSet = tgtExport->Target->Target->GetFileSet(fileSetName);
+
+ if (!tgtExport->FileSetGenerators.count(fileSet)) {
+ lg->IssueMessage(MessageType::FATAL_ERROR,
+ cmStrCat("File set \"", fileSetName,
+ "\" is listed in interface file sets of ",
+ tgtExport->Target->GetName(),
+ " but has not been exported"));
+ return false;
+ }
+ return true;
+ };
+
+ if (!std::all_of(interfaceFileSets.begin(), interfaceFileSets.end(),
+ fileSetInTargetExport)) {
+ return false;
+ }
}
+
+ return true;
}
void cmExportSet::AddTargetExport(std::unique_ptr<cmTargetExport> te)
diff --git a/Source/cmExportSet.h b/Source/cmExportSet.h
index 07deb11..b75a26d 100644
--- a/Source/cmExportSet.h
+++ b/Source/cmExportSet.h
@@ -25,7 +25,7 @@ public:
cmExportSet(const cmExportSet&) = delete;
cmExportSet& operator=(const cmExportSet&) = delete;
- void Compute(cmLocalGenerator* lg);
+ bool Compute(cmLocalGenerator* lg);
void AddTargetExport(std::unique_ptr<cmTargetExport> tgt);
diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h
index 1dd8a20..5c34fad 100644
--- a/Source/cmExportTryCompileFileGenerator.h
+++ b/Source/cmExportTryCompileFileGenerator.h
@@ -55,6 +55,9 @@ protected:
std::string GetFileSetFiles(cmGeneratorTarget* target, cmFileSet* fileSet,
cmTargetExport* te) override;
+ std::string GetCxxModulesDirectory() const override { return {}; }
+ void GenerateCxxModuleConfigInformation(std::ostream&) const override {}
+
private:
std::string FindTargets(const std::string& prop,
const cmGeneratorTarget* tgt,
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index dd0540c..0581802 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -27,6 +27,7 @@
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
+#include "cmInstallCxxModuleBmiGenerator.h"
#include "cmInstallDirectoryGenerator.h"
#include "cmInstallExportGenerator.h"
#include "cmInstallFileSetGenerator.h"
@@ -1092,6 +1093,21 @@ Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen)
if (installFileSet->GetOptional()) {
installer["isOptional"] = true;
}
+ } else if (auto* cxxModuleBmi =
+ dynamic_cast<cmInstallCxxModuleBmiGenerator*>(gen)) {
+ installer["type"] = "cxxModuleBmi";
+ installer["destination"] = cxxModuleBmi->GetDestination(this->Config);
+
+ auto const* target = cxxModuleBmi->GetTarget();
+ installer["cxxModuleBmiTarget"] = Json::objectValue;
+ installer["cxxModuleBmiTarget"]["id"] = TargetId(target, this->TopBuild);
+ installer["cxxModuleBmiTarget"]["index"] = this->TargetIndexMap[target];
+
+ // FIXME: Parse FilePermissions.
+ // FIXME: Parse MessageLevel.
+ if (cxxModuleBmi->GetOptional()) {
+ installer["isOptional"] = true;
+ }
}
// Add fields common to all install generators.
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 7d05347..bec9fb2 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -28,8 +28,8 @@
#include "cm_sys_stat.h"
-#include "cmAlgorithms.h"
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmCMakePath.h"
#include "cmCryptoHash.h"
#include "cmELF.h"
@@ -172,7 +172,8 @@ bool HandleReadCommand(std::vector<std::string> const& args,
.Bind("LIMIT"_s, &Arguments::Limit)
.Bind("HEX"_s, &Arguments::Hex);
- Arguments const arguments = parser.Parse(cmMakeRange(args).advance(3));
+ Arguments const arguments = parser.Parse(cmMakeRange(args).advance(3),
+ /*unparsedArguments=*/nullptr);
std::string fileName = fileNameArg;
if (!cmsys::SystemTools::FileIsFullPath(fileName)) {
@@ -200,13 +201,19 @@ bool HandleReadCommand(std::vector<std::string> const& args,
// is there a limit?
std::string::size_type sizeLimit = std::string::npos;
if (!arguments.Limit.empty()) {
- std::istringstream(arguments.Limit) >> sizeLimit;
+ unsigned long long limit;
+ if (cmStrToULongLong(arguments.Limit, &limit)) {
+ sizeLimit = static_cast<std::string::size_type>(limit);
+ }
}
// is there an offset?
cmsys::ifstream::off_type offset = 0;
if (!arguments.Offset.empty()) {
- std::istringstream(arguments.Offset) >> offset;
+ long long off;
+ if (cmStrToLongLong(arguments.Offset, &off)) {
+ offset = static_cast<cmsys::ifstream::off_type>(off);
+ }
}
file.seekg(offset, std::ios::beg); // explicit ios::beg for IBM VisualAge 6
@@ -953,42 +960,34 @@ bool HandleRPathChangeCommand(std::vector<std::string> const& args,
{
// Evaluate arguments.
std::string file;
- std::string oldRPath;
- std::string newRPath;
+ cm::optional<std::string> oldRPath;
+ cm::optional<std::string> newRPath;
bool removeEnvironmentRPath = false;
cmArgumentParser<void> parser;
std::vector<std::string> unknownArgs;
- std::vector<std::string> missingArgs;
- std::vector<std::string> parsedArgs;
parser.Bind("FILE"_s, file)
.Bind("OLD_RPATH"_s, oldRPath)
.Bind("NEW_RPATH"_s, newRPath)
.Bind("INSTALL_REMOVE_ENVIRONMENT_RPATH"_s, removeEnvironmentRPath);
- parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs,
- &parsedArgs);
+ ArgumentParser::ParseResult parseResult =
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs);
if (!unknownArgs.empty()) {
status.SetError(
cmStrCat("RPATH_CHANGE given unknown argument ", unknownArgs.front()));
return false;
}
- if (!missingArgs.empty()) {
- status.SetError(cmStrCat("RPATH_CHANGE \"", missingArgs.front(),
- "\" argument not given value."));
- return false;
+ if (parseResult.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (file.empty()) {
status.SetError("RPATH_CHANGE not given FILE option.");
return false;
}
- if (oldRPath.empty() &&
- std::find(parsedArgs.begin(), parsedArgs.end(), "OLD_RPATH") ==
- parsedArgs.end()) {
+ if (!oldRPath) {
status.SetError("RPATH_CHANGE not given OLD_RPATH option.");
return false;
}
- if (newRPath.empty() &&
- std::find(parsedArgs.begin(), parsedArgs.end(), "NEW_RPATH") ==
- parsedArgs.end()) {
+ if (!newRPath) {
status.SetError("RPATH_CHANGE not given NEW_RPATH option.");
return false;
}
@@ -1002,17 +1001,17 @@ bool HandleRPathChangeCommand(std::vector<std::string> const& args,
std::string emsg;
bool changed;
- if (!cmSystemTools::ChangeRPath(file, oldRPath, newRPath,
+ if (!cmSystemTools::ChangeRPath(file, *oldRPath, *newRPath,
removeEnvironmentRPath, &emsg, &changed)) {
status.SetError(cmStrCat("RPATH_CHANGE could not write new RPATH:\n ",
- newRPath, "\nto the file:\n ", file, "\n",
+ *newRPath, "\nto the file:\n ", file, "\n",
emsg));
success = false;
}
if (success) {
if (changed) {
std::string message =
- cmStrCat("Set runtime path of \"", file, "\" to \"", newRPath, '"');
+ cmStrCat("Set runtime path of \"", file, "\" to \"", *newRPath, '"');
status.GetMakefile().DisplayStatus(message, -1);
}
ft.Store(file);
@@ -1025,31 +1024,25 @@ bool HandleRPathSetCommand(std::vector<std::string> const& args,
{
// Evaluate arguments.
std::string file;
- std::string newRPath;
+ cm::optional<std::string> newRPath;
cmArgumentParser<void> parser;
std::vector<std::string> unknownArgs;
- std::vector<std::string> missingArgs;
- std::vector<std::string> parsedArgs;
parser.Bind("FILE"_s, file).Bind("NEW_RPATH"_s, newRPath);
- parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs,
- &parsedArgs);
+ ArgumentParser::ParseResult parseResult =
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs);
if (!unknownArgs.empty()) {
status.SetError(cmStrCat("RPATH_SET given unrecognized argument \"",
unknownArgs.front(), "\"."));
return false;
}
- if (!missingArgs.empty()) {
- status.SetError(cmStrCat("RPATH_SET \"", missingArgs.front(),
- "\" argument not given value."));
- return false;
+ if (parseResult.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (file.empty()) {
status.SetError("RPATH_SET not given FILE option.");
return false;
}
- if (newRPath.empty() &&
- std::find(parsedArgs.begin(), parsedArgs.end(), "NEW_RPATH") ==
- parsedArgs.end()) {
+ if (!newRPath) {
status.SetError("RPATH_SET not given NEW_RPATH option.");
return false;
}
@@ -1063,16 +1056,16 @@ bool HandleRPathSetCommand(std::vector<std::string> const& args,
std::string emsg;
bool changed;
- if (!cmSystemTools::SetRPath(file, newRPath, &emsg, &changed)) {
+ if (!cmSystemTools::SetRPath(file, *newRPath, &emsg, &changed)) {
status.SetError(cmStrCat("RPATH_SET could not write new RPATH:\n ",
- newRPath, "\nto the file:\n ", file, "\n",
+ *newRPath, "\nto the file:\n ", file, "\n",
emsg));
success = false;
}
if (success) {
if (changed) {
std::string message =
- cmStrCat("Set runtime path of \"", file, "\" to \"", newRPath, '"');
+ cmStrCat("Set runtime path of \"", file, "\" to \"", *newRPath, '"');
status.GetMakefile().DisplayStatus(message, -1);
}
ft.Store(file);
@@ -1087,18 +1080,16 @@ bool HandleRPathRemoveCommand(std::vector<std::string> const& args,
std::string file;
cmArgumentParser<void> parser;
std::vector<std::string> unknownArgs;
- std::vector<std::string> missingArgs;
parser.Bind("FILE"_s, file);
- parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs);
+ ArgumentParser::ParseResult parseResult =
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs);
if (!unknownArgs.empty()) {
status.SetError(
cmStrCat("RPATH_REMOVE given unknown argument ", unknownArgs.front()));
return false;
}
- if (!missingArgs.empty()) {
- status.SetError(cmStrCat("RPATH_REMOVE \"", missingArgs.front(),
- "\" argument not given value."));
- return false;
+ if (parseResult.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (file.empty()) {
status.SetError("RPATH_REMOVE not given FILE option.");
@@ -1135,31 +1126,25 @@ bool HandleRPathCheckCommand(std::vector<std::string> const& args,
{
// Evaluate arguments.
std::string file;
- std::string rpath;
+ cm::optional<std::string> rpath;
cmArgumentParser<void> parser;
std::vector<std::string> unknownArgs;
- std::vector<std::string> missingArgs;
- std::vector<std::string> parsedArgs;
parser.Bind("FILE"_s, file).Bind("RPATH"_s, rpath);
- parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs,
- &parsedArgs);
+ ArgumentParser::ParseResult parseResult =
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs);
if (!unknownArgs.empty()) {
status.SetError(
cmStrCat("RPATH_CHECK given unknown argument ", unknownArgs.front()));
return false;
}
- if (!missingArgs.empty()) {
- status.SetError(cmStrCat("RPATH_CHECK \"", missingArgs.front(),
- "\" argument not given value."));
- return false;
+ if (parseResult.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (file.empty()) {
status.SetError("RPATH_CHECK not given FILE option.");
return false;
}
- if (rpath.empty() &&
- std::find(parsedArgs.begin(), parsedArgs.end(), "RPATH") ==
- parsedArgs.end()) {
+ if (!rpath) {
status.SetError("RPATH_CHECK not given RPATH option.");
return false;
}
@@ -1168,7 +1153,7 @@ bool HandleRPathCheckCommand(std::vector<std::string> const& args,
// delete it. This is used during installation to re-install a file
// if its RPath will change.
if (cmSystemTools::FileExists(file, true) &&
- !cmSystemTools::CheckRPath(file, rpath)) {
+ !cmSystemTools::CheckRPath(file, *rpath)) {
cmSystemTools::RemoveFile(file);
}
@@ -1197,7 +1182,8 @@ bool HandleReadElfCommand(std::vector<std::string> const& args,
.Bind("RPATH"_s, &Arguments::RPath)
.Bind("RUNPATH"_s, &Arguments::RunPath)
.Bind("CAPTURE_ERROR"_s, &Arguments::Error);
- Arguments const arguments = parser.Parse(cmMakeRange(args).advance(2));
+ Arguments const arguments = parser.Parse(cmMakeRange(args).advance(2),
+ /*unparsedArguments=*/nullptr);
if (!cmSystemTools::FileExists(fileNameArg, true)) {
status.SetError(cmStrCat("READ_ELF given FILE \"", fileNameArg,
@@ -1250,9 +1236,9 @@ bool HandleRealPathCommand(std::vector<std::string> const& args,
return false;
}
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
- std::string BaseDirectory;
+ cm::optional<std::string> BaseDirectory;
bool ExpandTilde = false;
};
static auto const parser =
@@ -1261,22 +1247,18 @@ bool HandleRealPathCommand(std::vector<std::string> const& args,
.Bind("EXPAND_TILDE"_s, &Arguments::ExpandTilde);
std::vector<std::string> unparsedArguments;
- std::vector<std::string> keywordsMissingValue;
- std::vector<std::string> parsedKeywords;
auto arguments =
- parser.Parse(cmMakeRange(args).advance(3), &unparsedArguments,
- &keywordsMissingValue, &parsedKeywords);
+ parser.Parse(cmMakeRange(args).advance(3), &unparsedArguments);
if (!unparsedArguments.empty()) {
status.SetError("REAL_PATH called with unexpected arguments");
return false;
}
- if (!keywordsMissingValue.empty()) {
- status.SetError("BASE_DIRECTORY requires a value");
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
- if (parsedKeywords.empty()) {
+ if (!arguments.BaseDirectory) {
arguments.BaseDirectory = status.GetMakefile().GetCurrentSourceDirectory();
}
@@ -1295,7 +1277,7 @@ bool HandleRealPathCommand(std::vector<std::string> const& args,
}
cmCMakePath path(input, cmCMakePath::auto_format);
- path = path.Absolute(arguments.BaseDirectory).Normal();
+ path = path.Absolute(*arguments.BaseDirectory).Normal();
auto realPath = cmSystemTools::GetRealPath(path.GenericString());
status.GetMakefile().AddDefinition(args[2], realPath);
@@ -1938,7 +1920,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
std::string msg;
std::string actualHash = hash->HashFile(file);
if (actualHash == expectedHash) {
- msg = cmStrCat("returning early; file already exists with expected ",
+ msg = cmStrCat("skipping download as file already exists with expected ",
hashMatchMSG, '"');
if (!statusVar.empty()) {
status.GetMakefile().AddDefinition(statusVar, cmStrCat(0, ";\"", msg));
@@ -2495,17 +2477,18 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
return false;
}
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
- std::string Output;
- std::string Input;
- std::string Content;
- std::string Condition;
- std::string Target;
- std::string NewLineStyle;
+ cm::optional<std::string> Output;
+ cm::optional<std::string> Input;
+ cm::optional<std::string> Content;
+ cm::optional<std::string> Condition;
+ cm::optional<std::string> Target;
+ cm::optional<std::string> NewLineStyle;
bool NoSourcePermissions = false;
bool UseSourcePermissions = false;
- std::vector<std::string> FilePermissions;
+ ArgumentParser::NonEmpty<std::vector<std::string>> FilePermissions;
+ std::vector<cm::string_view> ParsedKeywords;
};
static auto const parser =
@@ -2518,18 +2501,15 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
.Bind("NO_SOURCE_PERMISSIONS"_s, &Arguments::NoSourcePermissions)
.Bind("USE_SOURCE_PERMISSIONS"_s, &Arguments::UseSourcePermissions)
.Bind("FILE_PERMISSIONS"_s, &Arguments::FilePermissions)
- .Bind("NEWLINE_STYLE"_s, &Arguments::NewLineStyle);
+ .Bind("NEWLINE_STYLE"_s, &Arguments::NewLineStyle)
+ .BindParsedKeywords(&Arguments::ParsedKeywords);
std::vector<std::string> unparsedArguments;
- std::vector<std::string> keywordsMissingValues;
- std::vector<std::string> parsedKeywords;
Arguments const arguments =
- parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments,
- &keywordsMissingValues, &parsedKeywords);
+ parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments);
- if (!keywordsMissingValues.empty()) {
- status.SetError("Incorrect arguments to GENERATE subcommand.");
- return false;
+ if (arguments.MaybeReportError(status.GetMakefile())) {
+ return true;
}
if (!unparsedArguments.empty()) {
@@ -2537,56 +2517,41 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
return false;
}
- bool mandatoryOptionsSpecified = false;
- if (parsedKeywords.size() > 1) {
- const bool outputOprionSpecified = parsedKeywords[0] == "OUTPUT"_s;
- const bool inputOrContentSpecified =
- parsedKeywords[1] == "INPUT"_s || parsedKeywords[1] == "CONTENT"_s;
- if (outputOprionSpecified && inputOrContentSpecified) {
- mandatoryOptionsSpecified = true;
- }
+ if (!arguments.Output || arguments.ParsedKeywords[0] != "OUTPUT"_s) {
+ status.SetError("GENERATE requires OUTPUT as first option.");
+ return false;
}
- if (!mandatoryOptionsSpecified) {
- status.SetError("Incorrect arguments to GENERATE subcommand.");
+ std::string const& output = *arguments.Output;
+
+ if (!arguments.Input && !arguments.Content) {
+ status.SetError("GENERATE requires INPUT or CONTENT option.");
return false;
}
+ const bool inputIsContent = arguments.ParsedKeywords[1] == "CONTENT"_s;
+ if (!inputIsContent && arguments.ParsedKeywords[1] == "INPUT") {
+ status.SetError("Unknown argument to GENERATE subcommand.");
+ }
+ std::string const& input =
+ inputIsContent ? *arguments.Content : *arguments.Input;
- const bool conditionOptionSpecified =
- std::find(parsedKeywords.begin(), parsedKeywords.end(), "CONDITION"_s) !=
- parsedKeywords.end();
- if (conditionOptionSpecified && arguments.Condition.empty()) {
+ if (arguments.Condition && arguments.Condition->empty()) {
status.SetError("CONDITION of sub-command GENERATE must not be empty "
"if specified.");
return false;
}
+ std::string const& condition =
+ arguments.Condition ? *arguments.Condition : std::string();
- const bool targetOptionSpecified =
- std::find(parsedKeywords.begin(), parsedKeywords.end(), "TARGET"_s) !=
- parsedKeywords.end();
- if (targetOptionSpecified && arguments.Target.empty()) {
+ if (arguments.Target && arguments.Target->empty()) {
status.SetError("TARGET of sub-command GENERATE must not be empty "
"if specified.");
return false;
}
+ std::string const& target =
+ arguments.Target ? *arguments.Target : std::string();
- const bool outputOptionSpecified =
- std::find(parsedKeywords.begin(), parsedKeywords.end(), "OUTPUT"_s) !=
- parsedKeywords.end();
- if (outputOptionSpecified && parsedKeywords[0] != "OUTPUT"_s) {
- status.SetError("Incorrect arguments to GENERATE subcommand.");
- return false;
- }
-
- const bool inputIsContent = parsedKeywords[1] != "INPUT"_s;
- if (inputIsContent && parsedKeywords[1] != "CONTENT") {
- status.SetError("Unknown argument to GENERATE subcommand.");
- }
-
- const bool newLineStyleSpecified =
- std::find(parsedKeywords.begin(), parsedKeywords.end(),
- "NEWLINE_STYLE"_s) != parsedKeywords.end();
cmNewLineStyle newLineStyle;
- if (newLineStyleSpecified) {
+ if (arguments.NewLineStyle) {
std::string errorMessage;
if (!newLineStyle.ReadFromArguments(args, errorMessage)) {
status.SetError(cmStrCat("GENERATE ", errorMessage));
@@ -2594,11 +2559,6 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
}
}
- std::string input = arguments.Input;
- if (inputIsContent) {
- input = arguments.Content;
- }
-
if (arguments.NoSourcePermissions && arguments.UseSourcePermissions) {
status.SetError("given both NO_SOURCE_PERMISSIONS and "
"USE_SOURCE_PERMISSIONS. Only one option allowed.");
@@ -2656,8 +2616,7 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
}
}
- AddEvaluationFile(input, arguments.Target, arguments.Output,
- arguments.Condition, inputIsContent,
+ AddEvaluationFile(input, target, output, condition, inputIsContent,
newLineStyle.GetCharacters(), permissions, status);
return true;
}
@@ -2836,7 +2795,11 @@ bool HandleTimestampCommand(std::vector<std::string> const& args,
unsigned int argsIndex = 1;
- const std::string& filename = args[argsIndex++];
+ std::string filename = args[argsIndex++];
+ if (!cmsys::SystemTools::FileIsFullPath(filename)) {
+ filename = cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/',
+ filename);
+ }
const std::string& outputVariable = args[argsIndex++];
@@ -3060,24 +3023,25 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
"\n ]])");
}
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
std::string ResolvedDependenciesVar;
std::string UnresolvedDependenciesVar;
std::string ConflictingDependenciesPrefix;
std::string RPathPrefix;
std::string BundleExecutable;
- std::vector<std::string> Executables;
- std::vector<std::string> Libraries;
- std::vector<std::string> Directories;
- std::vector<std::string> Modules;
- std::vector<std::string> PreIncludeRegexes;
- std::vector<std::string> PreExcludeRegexes;
- std::vector<std::string> PostIncludeRegexes;
- std::vector<std::string> PostExcludeRegexes;
- std::vector<std::string> PostIncludeFiles;
- std::vector<std::string> PostExcludeFiles;
- std::vector<std::string> PostExcludeFilesStrict;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Executables;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Libraries;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Directories;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Modules;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PreIncludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PreExcludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeFiles;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeFiles;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>>
+ PostExcludeFilesStrict;
};
static auto const parser =
@@ -3102,10 +3066,8 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
.Bind("POST_EXCLUDE_FILES_STRICT"_s, &Arguments::PostExcludeFilesStrict);
std::vector<std::string> unrecognizedArguments;
- std::vector<std::string> keywordsMissingValues;
auto parsedArgs =
- parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
- &keywordsMissingValues);
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments);
auto argIt = unrecognizedArguments.begin();
if (argIt != unrecognizedArguments.end()) {
status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\""));
@@ -3113,26 +3075,9 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
return false;
}
- const std::vector<std::string> LIST_ARGS = {
- "DIRECTORIES",
- "EXECUTABLES",
- "LIBRARIES",
- "MODULES",
- "POST_EXCLUDE_FILES",
- "POST_EXCLUDE_FILES_STRICT",
- "POST_EXCLUDE_REGEXES",
- "POST_INCLUDE_FILES",
- "POST_INCLUDE_REGEXES",
- "PRE_EXCLUDE_REGEXES",
- "PRE_INCLUDE_REGEXES",
- };
- auto kwbegin = keywordsMissingValues.cbegin();
- auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS);
- if (kwend != kwbegin) {
- status.SetError(cmStrCat("Keywords missing values:\n ",
- cmJoin(cmMakeRange(kwbegin, kwend), "\n ")));
+ if (parsedArgs.MaybeReportError(status.GetMakefile())) {
cmSystemTools::SetFatalErrorOccurred();
- return false;
+ return true;
}
cmRuntimeDependencyArchive archive(
@@ -3232,13 +3177,14 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
bool HandleConfigureCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
- std::string Output;
- std::string Content;
+ cm::optional<std::string> Output;
+ cm::optional<std::string> Content;
bool EscapeQuotes = false;
bool AtOnly = false;
- std::string NewlineStyle;
+ // "NEWLINE_STYLE" requires one value, but we use a custom check below.
+ ArgumentParser::Maybe<std::string> NewlineStyle;
};
static auto const parser =
@@ -3250,11 +3196,8 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
.Bind("NEWLINE_STYLE"_s, &Arguments::NewlineStyle);
std::vector<std::string> unrecognizedArguments;
- std::vector<std::string> keywordsMissingArguments;
- std::vector<std::string> parsedKeywords;
auto parsedArgs =
- parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
- &keywordsMissingArguments, &parsedKeywords);
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments);
auto argIt = unrecognizedArguments.begin();
if (argIt != unrecognizedArguments.end()) {
@@ -3264,28 +3207,20 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
return false;
}
- std::vector<std::string> mandatoryOptions{ "OUTPUT", "CONTENT" };
- for (auto const& e : mandatoryOptions) {
- const bool optionHasNoValue =
- std::find(keywordsMissingArguments.begin(),
- keywordsMissingArguments.end(),
- e) != keywordsMissingArguments.end();
- if (optionHasNoValue) {
- status.SetError(cmStrCat("CONFIGURE ", e, " option needs a value."));
- cmSystemTools::SetFatalErrorOccurred();
- return false;
- }
+ if (parsedArgs.MaybeReportError(status.GetMakefile())) {
+ cmSystemTools::SetFatalErrorOccurred();
+ return true;
}
- for (auto const& e : mandatoryOptions) {
- const bool optionGiven =
- std::find(parsedKeywords.begin(), parsedKeywords.end(), e) !=
- parsedKeywords.end();
- if (!optionGiven) {
- status.SetError(cmStrCat("CONFIGURE ", e, " option is mandatory."));
- cmSystemTools::SetFatalErrorOccurred();
- return false;
- }
+ if (!parsedArgs.Output) {
+ status.SetError("CONFIGURE OUTPUT option is mandatory.");
+ cmSystemTools::SetFatalErrorOccurred();
+ return false;
+ }
+ if (!parsedArgs.Content) {
+ status.SetError("CONFIGURE CONTENT option is mandatory.");
+ cmSystemTools::SetFatalErrorOccurred();
+ return false;
}
std::string errorMessage;
@@ -3297,7 +3232,7 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
// Check for generator expressions
std::string outputFile = cmSystemTools::CollapseFullPath(
- parsedArgs.Output, status.GetMakefile().GetCurrentBinaryDirectory());
+ *parsedArgs.Output, status.GetMakefile().GetCurrentBinaryDirectory());
std::string::size_type pos = outputFile.find_first_of("<>");
if (pos != std::string::npos) {
@@ -3346,7 +3281,7 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
fout.SetCopyIfDifferent(true);
// copy input to output and expand variables from input at the same time
- std::stringstream sin(parsedArgs.Content, std::ios::in);
+ std::stringstream sin(*parsedArgs.Content, std::ios::in);
std::string inLine;
std::string outLine;
bool hasNewLine = false;
@@ -3369,15 +3304,19 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
bool HandleArchiveCreateCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
std::string Output;
std::string Format;
std::string Compression;
std::string CompressionLevel;
- std::string MTime;
+ // "MTIME" should require one value, but it has long been accidentally
+ // accepted without one and treated as if an empty value were given.
+ // Fixing this would require a policy.
+ ArgumentParser::Maybe<std::string> MTime;
bool Verbose = false;
- std::vector<std::string> Paths;
+ // "PATHS" requires at least one value, but use a custom check below.
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Paths;
};
static auto const parser =
@@ -3391,10 +3330,8 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args,
.Bind("PATHS"_s, &Arguments::Paths);
std::vector<std::string> unrecognizedArguments;
- std::vector<std::string> keywordsMissingValues;
auto parsedArgs =
- parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
- &keywordsMissingValues);
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments);
auto argIt = unrecognizedArguments.begin();
if (argIt != unrecognizedArguments.end()) {
status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\""));
@@ -3402,16 +3339,9 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args,
return false;
}
- const std::vector<std::string> LIST_ARGS = {
- "OUTPUT", "FORMAT", "COMPRESSION", "COMPRESSION_LEVEL", "MTIME", "PATHS"
- };
- auto kwbegin = keywordsMissingValues.cbegin();
- auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS);
- if (kwend != kwbegin) {
- status.SetError(cmStrCat("Keywords missing values:\n ",
- cmJoin(cmMakeRange(kwbegin, kwend), "\n ")));
+ if (parsedArgs.MaybeReportError(status.GetMakefile())) {
cmSystemTools::SetFatalErrorOccurred();
- return false;
+ return true;
}
const char* knownFormats[] = {
@@ -3500,13 +3430,13 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args,
bool HandleArchiveExtractCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
std::string Input;
bool Verbose = false;
bool ListOnly = false;
std::string Destination;
- std::vector<std::string> Patterns;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Patterns;
bool Touch = false;
};
@@ -3519,10 +3449,8 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args,
.Bind("TOUCH"_s, &Arguments::Touch);
std::vector<std::string> unrecognizedArguments;
- std::vector<std::string> keywordsMissingValues;
auto parsedArgs =
- parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
- &keywordsMissingValues);
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments);
auto argIt = unrecognizedArguments.begin();
if (argIt != unrecognizedArguments.end()) {
status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\""));
@@ -3530,15 +3458,9 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args,
return false;
}
- const std::vector<std::string> LIST_ARGS = { "INPUT", "DESTINATION",
- "PATTERNS" };
- auto kwbegin = keywordsMissingValues.cbegin();
- auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS);
- if (kwend != kwbegin) {
- status.SetError(cmStrCat("Keywords missing values:\n ",
- cmJoin(cmMakeRange(kwbegin, kwend), "\n ")));
+ if (parsedArgs.MaybeReportError(status.GetMakefile())) {
cmSystemTools::SetFatalErrorOccurred();
- return false;
+ return true;
}
std::string inFile = parsedArgs.Input;
@@ -3593,10 +3515,15 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args,
return true;
}
-bool ValidateAndConvertPermissions(const std::vector<std::string>& permissions,
- mode_t& perms, cmExecutionStatus& status)
+bool ValidateAndConvertPermissions(
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> const&
+ permissions,
+ mode_t& perms, cmExecutionStatus& status)
{
- for (const auto& i : permissions) {
+ if (!permissions) {
+ return true;
+ }
+ for (const auto& i : *permissions) {
if (!cmFSPermissions::stringToModeT(i, perms)) {
status.SetError(i + " is an invalid permission specifier");
cmSystemTools::SetFatalErrorOccurred();
@@ -3628,11 +3555,14 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse,
globber.SetRecurse(recurse);
globber.SetRecurseListDirs(recurse);
- struct Arguments
+ struct Arguments : public ArgumentParser::ParseResult
{
- std::vector<std::string> Permissions;
- std::vector<std::string> FilePermissions;
- std::vector<std::string> DirectoryPermissions;
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>>
+ Permissions;
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>>
+ FilePermissions;
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>>
+ DirectoryPermissions;
};
static auto const parser =
@@ -3642,21 +3572,20 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse,
.Bind("DIRECTORY_PERMISSIONS"_s, &Arguments::DirectoryPermissions);
std::vector<std::string> pathEntries;
- std::vector<std::string> keywordsMissingValues;
- Arguments parsedArgs = parser.Parse(cmMakeRange(args).advance(1),
- &pathEntries, &keywordsMissingValues);
+ Arguments parsedArgs =
+ parser.Parse(cmMakeRange(args).advance(1), &pathEntries);
// check validity of arguments
- if (parsedArgs.Permissions.empty() && parsedArgs.FilePermissions.empty() &&
- parsedArgs.DirectoryPermissions.empty()) // no permissions given
+ if (!parsedArgs.Permissions && !parsedArgs.FilePermissions &&
+ !parsedArgs.DirectoryPermissions) // no permissions given
{
status.SetError("No permissions given");
cmSystemTools::SetFatalErrorOccurred();
return false;
}
- if (!parsedArgs.Permissions.empty() && !parsedArgs.FilePermissions.empty() &&
- !parsedArgs.DirectoryPermissions.empty()) // all keywords are used
+ if (parsedArgs.Permissions && parsedArgs.FilePermissions &&
+ parsedArgs.DirectoryPermissions) // all keywords are used
{
status.SetError("Remove either PERMISSIONS or FILE_PERMISSIONS or "
"DIRECTORY_PERMISSIONS from the invocation");
@@ -3664,12 +3593,9 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse,
return false;
}
- if (!keywordsMissingValues.empty()) {
- for (const auto& i : keywordsMissingValues) {
- status.SetError(i + " is not given any arguments");
- cmSystemTools::SetFatalErrorOccurred();
- }
- return false;
+ if (parsedArgs.MaybeReportError(status.GetMakefile())) {
+ cmSystemTools::SetFatalErrorOccurred();
+ return true;
}
// validate permissions
@@ -3713,7 +3639,7 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse,
if (cmSystemTools::FileExists(i, true)) {
bool success = true;
const mode_t& filePermissions =
- parsedArgs.FilePermissions.empty() ? perms : fperms;
+ parsedArgs.FilePermissions ? fperms : perms;
if (filePermissions) {
success = SetPermissions(i, filePermissions, status);
}
@@ -3725,7 +3651,7 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse,
else if (cmSystemTools::FileIsDirectory(i)) {
bool success = true;
const mode_t& directoryPermissions =
- parsedArgs.DirectoryPermissions.empty() ? perms : dperms;
+ parsedArgs.DirectoryPermissions ? dperms : perms;
if (directoryPermissions) {
success = SetPermissions(i, directoryPermissions, status);
}
diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx
index 91efc66..b8d345f 100644
--- a/Source/cmFindBase.cxx
+++ b/Source/cmFindBase.cxx
@@ -336,6 +336,43 @@ void cmFindBase::FillSystemEnvironmentPath()
paths.AddSuffixes(this->SearchPathSuffixes);
}
+namespace {
+struct entry_to_remove
+{
+ entry_to_remove(std::string const& name, cmMakefile* makefile)
+ : value()
+ {
+ if (cmValue to_skip = makefile->GetDefinition(
+ cmStrCat("_CMAKE_SYSTEM_PREFIX_PATH_", name, "_PREFIX_COUNT"))) {
+ cmStrToLong(to_skip, &count);
+ }
+ if (cmValue prefix_value = makefile->GetDefinition(
+ cmStrCat("_CMAKE_SYSTEM_PREFIX_PATH_", name, "_PREFIX_VALUE"))) {
+ value = *prefix_value;
+ }
+ }
+ bool valid() const { return count > 0 && !value.empty(); }
+
+ void remove_self(std::vector<std::string>& entries) const
+ {
+ if (this->valid()) {
+ long to_skip = this->count;
+ long index_to_remove = 0;
+ for (const auto& path : entries) {
+ if (path == this->value && --to_skip == 0) {
+ break;
+ }
+ ++index_to_remove;
+ }
+ entries.erase(entries.begin() + index_to_remove);
+ }
+ }
+
+ long count = -1;
+ std::string value;
+};
+}
+
void cmFindBase::FillCMakeSystemVariablePath()
{
cmSearchPath& paths = this->LabeledPaths[PathLabel::CMakeSystem];
@@ -356,38 +393,25 @@ void cmFindBase::FillCMakeSystemVariablePath()
// computed by `CMakeSystemSpecificInformation.cmake` while constructing
// `CMAKE_SYSTEM_PREFIX_PATH`. This ensures that if projects / toolchains
// have removed `CMAKE_INSTALL_PREFIX` from the list, we don't remove
- // some other entry by mistake
- long install_prefix_count = -1;
- std::string install_path_to_remove;
- if (cmValue to_skip = this->Makefile->GetDefinition(
- "_CMAKE_SYSTEM_PREFIX_PATH_INSTALL_PREFIX_COUNT")) {
- cmStrToLong(to_skip, &install_prefix_count);
- }
- if (cmValue install_value = this->Makefile->GetDefinition(
- "_CMAKE_SYSTEM_PREFIX_PATH_INSTALL_PREFIX_VALUE")) {
- install_path_to_remove = *install_value;
- }
+ // some other entry by mistake ( likewise for `CMAKE_STAGING_PREFIX` )
+ entry_to_remove install_entry("INSTALL", this->Makefile);
+ entry_to_remove staging_entry("STAGING", this->Makefile);
if (remove_install_prefix && install_prefix_in_list &&
- install_prefix_count > 0 && !install_path_to_remove.empty()) {
+ (install_entry.valid() || staging_entry.valid())) {
cmValue prefix_paths =
this->Makefile->GetDefinition("CMAKE_SYSTEM_PREFIX_PATH");
- // remove entry from CMAKE_SYSTEM_PREFIX_PATH
+ // remove entries from CMAKE_SYSTEM_PREFIX_PATH
std::vector<std::string> expanded = cmExpandedList(*prefix_paths);
- long index_to_remove = 0;
- for (const auto& path : expanded) {
- if (path == install_path_to_remove && --install_prefix_count == 0) {
- break;
- }
- ++index_to_remove;
- }
- expanded.erase(expanded.begin() + index_to_remove);
+ install_entry.remove_self(expanded);
+ staging_entry.remove_self(expanded);
+
paths.AddPrefixPaths(expanded,
this->Makefile->GetCurrentSourceDirectory().c_str());
} else if (add_install_prefix && !install_prefix_in_list) {
-
paths.AddCMakePrefixPath("CMAKE_INSTALL_PREFIX");
+ paths.AddCMakePrefixPath("CMAKE_STAGING_PREFIX");
paths.AddCMakePrefixPath("CMAKE_SYSTEM_PREFIX_PATH");
} else {
// Otherwise the current setup of `CMAKE_SYSTEM_PREFIX_PATH` is correct
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index 4ad9124..3f8378b 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -5,7 +5,6 @@
#include <algorithm>
#include <cassert>
#include <cstdio>
-#include <cstring>
#include <deque>
#include <functional>
#include <iterator>
@@ -43,8 +42,405 @@
# include <StorageDefs.h>
#endif
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <windows.h>
+// http://msdn.microsoft.com/en-us/library/aa384253%28v=vs.85%29.aspx
+# if !defined(KEY_WOW64_32KEY)
+# define KEY_WOW64_32KEY 0x0200
+# endif
+# if !defined(KEY_WOW64_64KEY)
+# define KEY_WOW64_64KEY 0x0100
+# endif
+#endif
+
class cmExecutionStatus;
-class cmFileList;
+
+namespace {
+
+template <template <typename> class Op>
+struct StrverscmpOp
+{
+ bool operator()(const std::string& lhs, const std::string& rhs) const
+ {
+ return Op<int>()(cmSystemTools::strverscmp(lhs, rhs), 0);
+ }
+};
+
+std::size_t collectPathsForDebug(std::string& buffer,
+ cmSearchPath const& searchPath,
+ std::size_t const startIndex = 0)
+{
+ const auto& paths = searchPath.GetPaths();
+ if (paths.empty()) {
+ buffer += " none\n";
+ return 0;
+ }
+ for (auto i = startIndex; i < paths.size(); i++) {
+ buffer += " " + paths[i].Path + "\n";
+ }
+ return paths.size();
+}
+
+#if !(defined(_WIN32) && !defined(__CYGWIN__))
+class cmFindPackageCommandHoldFile
+{
+ const char* File;
+
+public:
+ cmFindPackageCommandHoldFile(const char* const f)
+ : File(f)
+ {
+ }
+ ~cmFindPackageCommandHoldFile()
+ {
+ if (this->File) {
+ cmSystemTools::RemoveFile(this->File);
+ }
+ }
+ cmFindPackageCommandHoldFile(const cmFindPackageCommandHoldFile&) = delete;
+ cmFindPackageCommandHoldFile& operator=(
+ const cmFindPackageCommandHoldFile&) = delete;
+ void Release() { this->File = nullptr; }
+};
+#endif
+
+bool isDirentryToIgnore(const char* const fname)
+{
+ assert(fname != nullptr);
+ assert(fname[0] != 0);
+ return fname[0] == '.' &&
+ (fname[1] == 0 || (fname[1] == '.' && fname[2] == 0));
+}
+
+class cmAppendPathSegmentGenerator
+{
+public:
+ cmAppendPathSegmentGenerator(cm::string_view dirName)
+ : DirName{ dirName }
+ {
+ }
+
+ std::string GetNextCandidate(const std::string& parent)
+ {
+ if (this->NeedReset) {
+ return {};
+ }
+ this->NeedReset = true;
+ return cmStrCat(parent, '/', this->DirName);
+ }
+
+ void Reset() { this->NeedReset = false; }
+
+private:
+ const cm::string_view DirName;
+ bool NeedReset = false;
+};
+
+class cmEnumPathSegmentsGenerator
+{
+public:
+ cmEnumPathSegmentsGenerator(const std::vector<cm::string_view>& init)
+ : Names{ init }
+ , Current{ this->Names.get().cbegin() }
+ {
+ }
+
+ std::string GetNextCandidate(const std::string& parent)
+ {
+ if (this->Current != this->Names.get().cend()) {
+ return cmStrCat(parent, '/', *this->Current++);
+ }
+ return {};
+ }
+
+ void Reset() { this->Current = this->Names.get().cbegin(); }
+
+private:
+ std::reference_wrapper<const std::vector<cm::string_view>> Names;
+ std::vector<cm::string_view>::const_iterator Current;
+};
+
+class cmCaseInsensitiveDirectoryListGenerator
+{
+public:
+ cmCaseInsensitiveDirectoryListGenerator(cm::string_view name)
+ : DirectoryLister{}
+ , DirName{ name }
+ {
+ }
+
+ std::string GetNextCandidate(const std::string& parent)
+ {
+ if (!this->Loaded) {
+ this->CurrentIdx = 0ul;
+ this->Loaded = true;
+ if (!this->DirectoryLister.Load(parent)) {
+ return {};
+ }
+ }
+
+ while (this->CurrentIdx < this->DirectoryLister.GetNumberOfFiles()) {
+ const char* const fname =
+ this->DirectoryLister.GetFile(this->CurrentIdx++);
+ if (isDirentryToIgnore(fname)) {
+ continue;
+ }
+ if (cmsysString_strcasecmp(fname, this->DirName.data()) == 0) {
+ auto candidate = cmStrCat(parent, '/', fname);
+ if (cmSystemTools::FileIsDirectory(candidate)) {
+ return candidate;
+ }
+ }
+ }
+ return {};
+ }
+
+ void Reset() { this->Loaded = false; }
+
+private:
+ cmsys::Directory DirectoryLister;
+ const cm::string_view DirName;
+ unsigned long CurrentIdx = 0ul;
+ bool Loaded = false;
+};
+
+class cmDirectoryListGenerator
+{
+public:
+ cmDirectoryListGenerator(std::vector<std::string> const& names)
+ : Names{ names }
+ , Matches{}
+ , Current{ this->Matches.cbegin() }
+ {
+ }
+ virtual ~cmDirectoryListGenerator() = default;
+
+ std::string GetNextCandidate(const std::string& parent)
+ {
+ // Construct a list of matches if not yet
+ if (this->Matches.empty()) {
+ cmsys::Directory directoryLister;
+ // ALERT `Directory::Load()` keeps only names
+ // internally and LOST entry type from `dirent`.
+ // So, `Directory::FileIsDirectory` gonna use
+ // `SystemTools::FileIsDirectory()` and waste a syscall.
+ // TODO Need to enhance the `Directory` class.
+ directoryLister.Load(parent);
+
+ // ATTENTION Is it guaranteed that first two entries are
+ // `.` and `..`?
+ // TODO If so, just start with index 2 and drop the
+ // `isDirentryToIgnore(i)` condition to check.
+ for (auto i = 0ul; i < directoryLister.GetNumberOfFiles(); ++i) {
+ const char* const fname = directoryLister.GetFile(i);
+ if (isDirentryToIgnore(fname)) {
+ continue;
+ }
+
+ for (const auto& n : this->Names.get()) {
+ // NOTE Customization point for `cmMacProjectDirectoryListGenerator`
+ const auto name = this->TransformNameBeforeCmp(n);
+ // Skip entries that don't match and non-directories.
+ // ATTENTION BTW, original code also didn't check if it's a symlink
+ // to a directory!
+ const auto equal =
+ (cmsysString_strncasecmp(fname, name.c_str(), name.length()) == 0);
+ if (equal && directoryLister.FileIsDirectory(i)) {
+ this->Matches.emplace_back(fname);
+ }
+ }
+ }
+ // NOTE Customization point for `cmProjectDirectoryListGenerator`
+ this->OnMatchesLoaded();
+
+ this->Current = this->Matches.cbegin();
+ }
+
+ if (this->Current != this->Matches.cend()) {
+ auto candidate = cmStrCat(parent, '/', *this->Current++);
+ return candidate;
+ }
+
+ return {};
+ }
+
+ void Reset()
+ {
+ this->Matches.clear();
+ this->Current = this->Matches.cbegin();
+ }
+
+protected:
+ virtual void OnMatchesLoaded() {}
+ virtual std::string TransformNameBeforeCmp(std::string same) { return same; }
+
+ std::reference_wrapper<const std::vector<std::string>> Names;
+ std::vector<std::string> Matches;
+ std::vector<std::string>::const_iterator Current;
+};
+
+class cmProjectDirectoryListGenerator : public cmDirectoryListGenerator
+{
+public:
+ cmProjectDirectoryListGenerator(std::vector<std::string> const& names,
+ cmFindPackageCommand::SortOrderType so,
+ cmFindPackageCommand::SortDirectionType sd)
+ : cmDirectoryListGenerator{ names }
+ , SortOrder{ so }
+ , SortDirection{ sd }
+ {
+ }
+
+protected:
+ void OnMatchesLoaded() override
+ {
+ // check if there is a specific sorting order to perform
+ if (this->SortOrder != cmFindPackageCommand::None) {
+ cmFindPackageCommand::Sort(this->Matches.begin(), this->Matches.end(),
+ this->SortOrder, this->SortDirection);
+ }
+ }
+
+private:
+ // sort parameters
+ const cmFindPackageCommand::SortOrderType SortOrder;
+ const cmFindPackageCommand::SortDirectionType SortDirection;
+};
+
+class cmMacProjectDirectoryListGenerator : public cmDirectoryListGenerator
+{
+public:
+ cmMacProjectDirectoryListGenerator(const std::vector<std::string>& names,
+ cm::string_view ext)
+ : cmDirectoryListGenerator{ names }
+ , Extension{ ext }
+ {
+ }
+
+protected:
+ std::string TransformNameBeforeCmp(std::string name) override
+ {
+ return cmStrCat(name, this->Extension);
+ }
+
+private:
+ const cm::string_view Extension;
+};
+
+class cmFileListGeneratorGlob
+{
+public:
+ cmFileListGeneratorGlob(cm::string_view pattern)
+ : Pattern(pattern)
+ , Files{}
+ , Current{}
+ {
+ }
+
+ std::string GetNextCandidate(const std::string& parent)
+ {
+ if (this->Files.empty()) {
+ // Glob the set of matching files.
+ std::string expr = cmStrCat(parent, this->Pattern);
+ cmsys::Glob g;
+ if (!g.FindFiles(expr)) {
+ return {};
+ }
+ this->Files = g.GetFiles();
+ this->Current = this->Files.cbegin();
+ }
+
+ // Skip non-directories
+ for (; this->Current != this->Files.cend() &&
+ !cmSystemTools::FileIsDirectory(*this->Current);
+ ++this->Current) {
+ }
+
+ return (this->Current != this->Files.cend()) ? *this->Current++
+ : std::string{};
+ }
+
+ void Reset()
+ {
+ this->Files.clear();
+ this->Current = this->Files.cbegin();
+ }
+
+private:
+ cm::string_view Pattern;
+ std::vector<std::string> Files;
+ std::vector<std::string>::const_iterator Current;
+};
+
+#if defined(__LCC__)
+# define CM_LCC_DIAG_SUPPRESS_1222
+# pragma diag_suppress 1222 // invalid error number (3288, but works anyway)
+# define CM_LCC_DIAG_SUPPRESS_3288
+# pragma diag_suppress 3288 // parameter was declared but never referenced
+#endif
+
+void ResetGenerator()
+{
+}
+
+template <typename Generator>
+void ResetGenerator(Generator&& generator)
+{
+ std::forward<Generator&&>(generator).Reset();
+}
+
+template <typename Generator, typename... Generators>
+void ResetGenerator(Generator&& generator, Generators&&... generators)
+{
+ ResetGenerator(std::forward<Generator&&>(generator));
+ ResetGenerator(std::forward<Generators&&>(generators)...);
+}
+
+template <typename CallbackFn>
+bool TryGeneratedPaths(CallbackFn&& filesCollector,
+ const std::string& fullPath)
+{
+ assert(!fullPath.empty() && fullPath.back() != '/');
+ return std::forward<CallbackFn&&>(filesCollector)(fullPath + '/');
+}
+
+template <typename CallbackFn, typename Generator, typename... Rest>
+bool TryGeneratedPaths(CallbackFn&& filesCollector,
+ const std::string& startPath, Generator&& gen,
+ Rest&&... tail)
+{
+ ResetGenerator(std::forward<Generator&&>(gen));
+ for (auto path = gen.GetNextCandidate(startPath); !path.empty();
+ path = gen.GetNextCandidate(startPath)) {
+ ResetGenerator(std::forward<Rest&&>(tail)...);
+ if (TryGeneratedPaths(std::forward<CallbackFn&&>(filesCollector), path,
+ std::forward<Rest&&>(tail)...)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+#ifdef CM_LCC_DIAG_SUPPRESS_3288
+# undef CM_LCC_DIAG_SUPPRESS_3288
+# pragma diag_default 3288
+#endif
+
+#ifdef CM_LCC_DIAG_SUPPRESS_1222
+# undef CM_LCC_DIAG_SUPPRESS_1222
+# pragma diag_default 1222
+#endif
+
+// Parse the version number and store the results that were
+// successfully parsed.
+int parseVersion(const std::string& version, unsigned int& major,
+ unsigned int& minor, unsigned int& patch, unsigned int& tweak)
+{
+ return std::sscanf(version.c_str(), "%u.%u.%u.%u", &major, &minor, &patch,
+ &tweak);
+}
+
+} // anonymous namespace
cmFindPackageCommand::PathLabel
cmFindPackageCommand::PathLabel::PackageRedirect("PACKAGE_REDIRECT");
@@ -60,25 +456,10 @@ const cm::string_view cmFindPackageCommand::VERSION_ENDPOINT_INCLUDED(
const cm::string_view cmFindPackageCommand::VERSION_ENDPOINT_EXCLUDED(
"EXCLUDE");
-struct StrverscmpGreater
-{
- bool operator()(const std::string& lhs, const std::string& rhs) const
- {
- return cmSystemTools::strverscmp(lhs, rhs) > 0;
- }
-};
-
-struct StrverscmpLesser
-{
- bool operator()(const std::string& lhs, const std::string& rhs) const
- {
- return cmSystemTools::strverscmp(lhs, rhs) < 0;
- }
-};
-
void cmFindPackageCommand::Sort(std::vector<std::string>::iterator begin,
std::vector<std::string>::iterator end,
- SortOrderType order, SortDirectionType dir)
+ SortOrderType const order,
+ SortDirectionType const dir)
{
if (order == Name_order) {
if (dir == Dec) {
@@ -86,14 +467,13 @@ void cmFindPackageCommand::Sort(std::vector<std::string>::iterator begin,
} else {
std::sort(begin, end);
}
- } else if (order == Natural)
- // natural order uses letters and numbers (contiguous numbers digit are
- // compared such that e.g. 000 00 < 01 < 010 < 09 < 0 < 1 < 9 < 10
- {
+ } else if (order == Natural) {
+ // natural order uses letters and numbers (contiguous numbers digit are
+ // compared such that e.g. 000 00 < 01 < 010 < 09 < 0 < 1 < 9 < 10
if (dir == Dec) {
- std::sort(begin, end, StrverscmpGreater());
+ std::sort(begin, end, StrverscmpOp<std::greater>());
} else {
- std::sort(begin, end, StrverscmpLesser());
+ std::sort(begin, end, StrverscmpOp<std::less>());
}
}
// else do not sort
@@ -113,11 +493,10 @@ cmFindPackageCommand::cmFindPackageCommand(cmExecutionStatus& status)
void cmFindPackageCommand::AppendSearchPathGroups()
{
- std::vector<cmFindCommon::PathLabel>* labels;
-
// Update the All group with new paths. Note that package redirection must
// take precedence over everything else, so it has to be first in the array.
- labels = &this->PathGroupLabelMap[PathGroup::All];
+ std::vector<cmFindCommon::PathLabel>* const labels =
+ &this->PathGroupLabelMap[PathGroup::All];
labels->insert(labels->begin(), PathLabel::PackageRedirect);
labels->insert(
std::find(labels->begin(), labels->end(), PathLabel::CMakeSystem),
@@ -147,15 +526,15 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
}
// Lookup required version of CMake.
- if (cmValue rv =
+ if (cmValue const rv =
this->Makefile->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
unsigned int v[3] = { 0, 0, 0 };
- sscanf(rv->c_str(), "%u.%u.%u", &v[0], &v[1], &v[2]);
+ std::sscanf(rv->c_str(), "%u.%u.%u", &v[0], &v[1], &v[2]);
this->RequiredCMakeVersion = CMake_VERSION_ENCODE(v[0], v[1], v[2]);
}
// Lookup target architecture, if any.
- if (cmValue arch =
+ if (cmValue const arch =
this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE")) {
this->LibraryArchitecture = *arch;
}
@@ -184,7 +563,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
// Check if User Package Registry should be disabled
// The `CMAKE_FIND_USE_PACKAGE_REGISTRY` has
// priority over the deprecated CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY
- if (cmValue def =
+ if (cmValue const def =
this->Makefile->GetDefinition("CMAKE_FIND_USE_PACKAGE_REGISTRY")) {
this->NoUserRegistry = !cmIsOn(*def);
} else if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY")) {
@@ -194,7 +573,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
// Check if System Package Registry should be disabled
// The `CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY` has
// priority over the deprecated CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY
- if (cmValue def = this->Makefile->GetDefinition(
+ if (cmValue const def = this->Makefile->GetDefinition(
"CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY")) {
this->NoSystemRegistry = !cmIsOn(*def);
} else if (this->Makefile->IsOn(
@@ -208,7 +587,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
}
// Check if Sorting should be enabled
- if (cmValue so =
+ if (cmValue const so =
this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_SORT_ORDER")) {
if (*so == "NAME") {
@@ -219,7 +598,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
this->SortOrder = None;
}
}
- if (cmValue sd =
+ if (cmValue const sd =
this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_SORT_DIRECTION")) {
this->SortDirection = (*sd == "ASC") ? Asc : Dec;
}
@@ -265,9 +644,9 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
cmsys::RegularExpression versionRegex(
R"V(^([0-9]+(\.[0-9]+)*)(\.\.\.(<?)([0-9]+(\.[0-9]+)*))?$)V");
bool haveVersion = false;
- std::set<unsigned int> configArgs;
- std::set<unsigned int> moduleArgs;
- for (unsigned int i = 1; i < args.size(); ++i) {
+ std::vector<std::size_t> configArgs;
+ std::vector<std::size_t> moduleArgs;
+ for (std::size_t i = 1u; i < args.size(); ++i) {
if (args[i] == "QUIET") {
this->Quiet = true;
doing = DoingNone;
@@ -281,17 +660,17 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
this->GlobalScope = true;
doing = DoingNone;
} else if (args[i] == "MODULE") {
- moduleArgs.insert(i);
+ moduleArgs.push_back(i);
doing = DoingNone;
// XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
// NOLINTNEXTLINE(bugprone-branch-clone)
} else if (args[i] == "CONFIG") {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingNone;
// XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
// NOLINTNEXTLINE(bugprone-branch-clone)
} else if (args[i] == "NO_MODULE") {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingNone;
} else if (args[i] == "REQUIRED") {
this->Required = true;
@@ -301,36 +680,36 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
} else if (args[i] == "OPTIONAL_COMPONENTS") {
doing = DoingOptionalComponents;
} else if (args[i] == "NAMES") {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingNames;
} else if (args[i] == "PATHS") {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingPaths;
} else if (args[i] == "HINTS") {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingHints;
} else if (args[i] == "PATH_SUFFIXES") {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingPathSuffixes;
} else if (args[i] == "CONFIGS") {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingConfigs;
} else if (args[i] == "NO_POLICY_SCOPE") {
this->PolicyScope = false;
doing = DoingNone;
} else if (args[i] == "NO_CMAKE_PACKAGE_REGISTRY") {
this->NoUserRegistry = true;
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingNone;
} else if (args[i] == "NO_CMAKE_SYSTEM_PACKAGE_REGISTRY") {
this->NoSystemRegistry = true;
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingNone;
// XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
// NOLINTNEXTLINE(bugprone-branch-clone)
} else if (args[i] == "NO_CMAKE_BUILDS_PATH") {
// Ignore legacy option.
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingNone;
} else if (args[i] == "REGISTRY_VIEW") {
if (++i == args.size()) {
@@ -347,7 +726,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
return false;
}
} else if (this->CheckCommonArgument(args[i])) {
- configArgs.insert(i);
+ configArgs.push_back(i);
doing = DoingNone;
} else if ((doing == DoingComponents) ||
(doing == DoingOptionalComponents)) {
@@ -361,8 +740,8 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
requiredComponents.insert(args[i]);
}
- std::string req_var = this->Name + "_FIND_REQUIRED_" + args[i];
- componentVarDefs.emplace_back(req_var, isRequired);
+ componentVarDefs.emplace_back(this->Name + "_FIND_REQUIRED_" + args[i],
+ isRequired);
// Append to the list of required components.
components += components_sep;
@@ -420,11 +799,11 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
if (!this->UseFindModules && !this->UseConfigFiles) {
std::ostringstream e;
e << "given options exclusive to Module mode:\n";
- for (unsigned int si : moduleArgs) {
+ for (auto si : moduleArgs) {
e << " " << args[si] << "\n";
}
e << "and options exclusive to Config mode:\n";
- for (unsigned int si : configArgs) {
+ for (auto si : configArgs) {
e << " " << args[si] << "\n";
}
e << "The options are incompatible.";
@@ -443,20 +822,20 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
if (this->VersionComplete.empty() || components.empty()) {
// Check whether we are recursing inside "Find<name>.cmake" within
// another find_package(<name>) call.
- std::string mod = cmStrCat(this->Name, "_FIND_MODULE");
+ std::string const mod = cmStrCat(this->Name, "_FIND_MODULE");
if (this->Makefile->IsOn(mod)) {
if (this->VersionComplete.empty()) {
// Get version information from the outer call if necessary.
// Requested version string.
- std::string ver = cmStrCat(this->Name, "_FIND_VERSION_COMPLETE");
+ std::string const ver = cmStrCat(this->Name, "_FIND_VERSION_COMPLETE");
this->VersionComplete = this->Makefile->GetSafeDefinition(ver);
// Whether an exact version is required.
- std::string exact = cmStrCat(this->Name, "_FIND_VERSION_EXACT");
+ std::string const exact = cmStrCat(this->Name, "_FIND_VERSION_EXACT");
this->VersionExact = this->Makefile->IsOn(exact);
}
if (components.empty()) {
- std::string components_var = this->Name + "_FIND_COMPONENTS";
+ std::string const components_var = this->Name + "_FIND_COMPONENTS";
components = this->Makefile->GetSafeDefinition(components_var);
}
}
@@ -497,15 +876,6 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
return false;
}
- // Parse the version number and store the results that were
- // successfully parsed.
- auto parseVersion = [](const std::string& version, unsigned int& major,
- unsigned int& minor, unsigned int& patch,
- unsigned int& tweak) -> unsigned int {
- return sscanf(version.c_str(), "%u.%u.%u.%u", &major, &minor, &patch,
- &tweak);
- };
-
if (!this->Version.empty()) {
this->VersionCount =
parseVersion(this->Version, this->VersionMajor, this->VersionMinor,
@@ -533,7 +903,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
}
}
- std::string disableFindPackageVar =
+ std::string const disableFindPackageVar =
cmStrCat("CMAKE_DISABLE_FIND_PACKAGE_", this->Name);
if (this->Makefile->IsOn(disableFindPackageVar)) {
if (this->Required) {
@@ -557,8 +927,8 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
// A dependency provider (if set) gets first look before other methods.
// We do this before modifying the package root path stack because a
// provider might use methods that ignore that.
- cmState* state = this->Makefile->GetState();
- cmState::Command providerCommand = state->GetDependencyProviderCommand(
+ cmState* const state = this->Makefile->GetState();
+ cmState::Command const providerCommand = state->GetDependencyProviderCommand(
cmDependencyProvider::Method::FindPackage);
if (bypassProvider) {
if (this->DebugMode && providerCommand) {
@@ -725,11 +1095,8 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
"package configuration file provided by "
<< this->Name << " (" << this->Name << "Config.cmake or "
<< cmSystemTools::LowerCase(this->Name)
- << "-config.cmake). "
- "Otherwise make Find"
- << this->Name
- << ".cmake available in "
- "CMAKE_MODULE_PATH.";
+ << "-config.cmake). Otherwise make Find" << this->Name
+ << ".cmake available in CMAKE_MODULE_PATH.";
}
aw << "\n"
"(Variable CMAKE_FIND_PACKAGE_WARN_NO_MODULE enabled this "
@@ -813,9 +1180,9 @@ bool cmFindPackageCommand::FindPackageUsingConfigMode()
void cmFindPackageCommand::SetVersionVariables(
const std::function<void(const std::string&, cm::string_view)>&
addDefinition,
- const std::string& prefix, const std::string& version, unsigned int count,
- unsigned int major, unsigned int minor, unsigned int patch,
- unsigned int tweak)
+ const std::string& prefix, const std::string& version,
+ const unsigned int count, const unsigned int major, const unsigned int minor,
+ const unsigned int patch, const unsigned int tweak)
{
addDefinition(prefix, version);
@@ -910,7 +1277,7 @@ void cmFindPackageCommand::SetModuleVariables(
}
void cmFindPackageCommand::AddFindDefinition(const std::string& var,
- cm::string_view value)
+ const cm::string_view value)
{
if (cmValue old = this->Makefile->GetDefinition(var)) {
this->OriginalDefs[var].exists = true;
@@ -954,7 +1321,7 @@ bool cmFindPackageCommand::FindModule(bool& found)
if (!mfile.empty()) {
if (system) {
- auto it = this->DeprecatedFindModules.find(this->Name);
+ auto const it = this->DeprecatedFindModules.find(this->Name);
if (it != this->DeprecatedFindModules.end()) {
cmPolicies::PolicyStatus status =
this->Makefile->GetPolicyStatus(it->second);
@@ -978,13 +1345,13 @@ bool cmFindPackageCommand::FindModule(bool& found)
// Load the module we found, and set "<name>_FIND_MODULE" to true
// while inside it.
found = true;
- std::string var = cmStrCat(this->Name, "_FIND_MODULE");
+ std::string const var = cmStrCat(this->Name, "_FIND_MODULE");
this->Makefile->AddDefinition(var, "1");
bool result = this->ReadListFile(mfile, DoPolicyScope);
this->Makefile->RemoveDefinition(var);
if (this->DebugMode) {
- std::string foundVar = cmStrCat(this->Name, "_FOUND");
+ std::string const foundVar = cmStrCat(this->Name, "_FOUND");
if (this->Makefile->IsDefinitionSet(foundVar) &&
!this->Makefile->IsOn(foundVar)) {
@@ -999,7 +1366,7 @@ bool cmFindPackageCommand::FindModule(bool& found)
}
bool cmFindPackageCommand::HandlePackageMode(
- HandlePackageModeType handlePackageModeType)
+ const HandlePackageModeType handlePackageModeType)
{
this->ConsideredConfigs.clear();
@@ -1042,8 +1409,9 @@ bool cmFindPackageCommand::HandlePackageMode(
}
}
- std::string foundVar = cmStrCat(this->Name, "_FOUND");
- std::string notFoundMessageVar = cmStrCat(this->Name, "_NOT_FOUND_MESSAGE");
+ std::string const foundVar = cmStrCat(this->Name, "_FOUND");
+ std::string const notFoundMessageVar =
+ cmStrCat(this->Name, "_NOT_FOUND_MESSAGE");
std::string notFoundMessage;
// If the directory for the config file was found, try to read the file.
@@ -1123,8 +1491,9 @@ bool cmFindPackageCommand::HandlePackageMode(
<< (this->VersionExact ? "exactly matches" : "is compatible with")
<< " requested version "
<< (this->VersionRange.empty() ? "" : "range ") << "\""
- << this->VersionComplete << "\".\n"
- << "The following configuration files were considered but not "
+ << this->VersionComplete
+ << "\".\n"
+ "The following configuration files were considered but not "
"accepted:\n";
for (ConfigFileInfo const& info :
@@ -1172,8 +1541,9 @@ bool cmFindPackageCommand::HandlePackageMode(
"package or SDK, be sure it has been installed.";
} else // if(!this->UseFindModules && !this->UseConfigFiles)
{
- e << "No \"Find" << this->Name << ".cmake\" found in "
- << "CMAKE_MODULE_PATH.";
+ e << "No \"Find" << this->Name
+ << ".cmake\" found in "
+ "CMAKE_MODULE_PATH.";
aw
<< "Find" << this->Name
@@ -1217,16 +1587,16 @@ bool cmFindPackageCommand::HandlePackageMode(
this->Makefile->AddDefinition(foundVar, found ? "1" : "0");
// Set a variable naming the configuration file that was found.
- std::string fileVar = cmStrCat(this->Name, "_CONFIG");
+ std::string const fileVar = cmStrCat(this->Name, "_CONFIG");
if (found) {
this->Makefile->AddDefinition(fileVar, this->FileFound);
} else {
this->Makefile->RemoveDefinition(fileVar);
}
- std::string consideredConfigsVar =
+ std::string const consideredConfigsVar =
cmStrCat(this->Name, "_CONSIDERED_CONFIGS");
- std::string consideredVersionsVar =
+ std::string const consideredVersionsVar =
cmStrCat(this->Name, "_CONSIDERED_VERSIONS");
std::string consideredConfigFiles;
@@ -1312,7 +1682,7 @@ bool cmFindPackageCommand::FindConfig()
void cmFindPackageCommand::SetConfigDirCacheVariable(const std::string& value)
{
- std::string help =
+ std::string const help =
cmStrCat("The directory containing a CMake configuration file for ",
this->Name, '.');
this->Makefile->AddCacheDefinition(this->Variable, value, help.c_str(),
@@ -1351,7 +1721,7 @@ bool cmFindPackageCommand::FindAppBundleConfig()
}
bool cmFindPackageCommand::ReadListFile(const std::string& f,
- PolicyScopeRule psr)
+ const PolicyScopeRule psr)
{
const bool noPolicyScope = !this->PolicyScope || psr == NoPolicyScope;
@@ -1362,12 +1732,12 @@ bool cmFindPackageCommand::ReadListFile(const std::string& f,
if (this->Makefile->ReadDependentFile(f, noPolicyScope)) {
return true;
}
- std::string e = cmStrCat("Error reading CMake code from \"", f, "\".");
+ std::string const e = cmStrCat("Error reading CMake code from \"", f, "\".");
this->SetError(e);
return false;
}
-void cmFindPackageCommand::AppendToFoundProperty(bool found)
+void cmFindPackageCommand::AppendToFoundProperty(const bool found)
{
std::vector<std::string> foundContents;
cmValue foundProp =
@@ -1410,27 +1780,28 @@ void cmFindPackageCommand::AppendToFoundProperty(bool found)
void cmFindPackageCommand::AppendSuccessInformation()
{
{
- std::string transitivePropName =
+ std::string const transitivePropName =
cmStrCat("_CMAKE_", this->Name, "_TRANSITIVE_DEPENDENCY");
this->Makefile->GetState()->SetGlobalProperty(transitivePropName, "False");
}
- std::string found = cmStrCat(this->Name, "_FOUND");
- std::string upperFound = cmSystemTools::UpperCase(found);
+ std::string const found = cmStrCat(this->Name, "_FOUND");
+ std::string const upperFound = cmSystemTools::UpperCase(found);
- bool upperResult = this->Makefile->IsOn(upperFound);
- bool result = this->Makefile->IsOn(found);
- bool packageFound = (result || upperResult);
+ bool const upperResult = this->Makefile->IsOn(upperFound);
+ bool const result = this->Makefile->IsOn(found);
+ bool const packageFound = (result || upperResult);
this->AppendToFoundProperty(packageFound);
// Record whether the find was quiet or not, so this can be used
// e.g. in FeatureSummary.cmake
- std::string quietInfoPropName = cmStrCat("_CMAKE_", this->Name, "_QUIET");
+ std::string const quietInfoPropName =
+ cmStrCat("_CMAKE_", this->Name, "_QUIET");
this->Makefile->GetState()->SetGlobalProperty(
quietInfoPropName, this->Quiet ? "TRUE" : "FALSE");
// set a global property to record the required version of this package
- std::string versionInfoPropName =
+ std::string const versionInfoPropName =
cmStrCat("_CMAKE_", this->Name, "_REQUIRED_VERSION");
std::string versionInfo;
if (!this->VersionRange.empty()) {
@@ -1442,28 +1813,13 @@ void cmFindPackageCommand::AppendSuccessInformation()
this->Makefile->GetState()->SetGlobalProperty(versionInfoPropName,
versionInfo.c_str());
if (this->Required) {
- std::string requiredInfoPropName =
+ std::string const requiredInfoPropName =
cmStrCat("_CMAKE_", this->Name, "_TYPE");
this->Makefile->GetState()->SetGlobalProperty(requiredInfoPropName,
"REQUIRED");
}
}
-inline std::size_t collectPathsForDebug(std::string& buffer,
- cmSearchPath const& searchPath,
- std::size_t startIndex = 0)
-{
- const auto& paths = searchPath.GetPaths();
- if (paths.empty()) {
- buffer += " none\n";
- return 0;
- }
- for (std::size_t i = startIndex; i < paths.size(); i++) {
- buffer += " " + paths[i].Path + "\n";
- }
- return paths.size();
-}
-
void cmFindPackageCommand::ComputePrefixes()
{
this->FillPrefixesPackageRedirect();
@@ -1674,14 +2030,6 @@ void cmFindPackageCommand::FillPrefixesSystemRegistry()
}
#if defined(_WIN32) && !defined(__CYGWIN__)
-# include <windows.h>
-// http://msdn.microsoft.com/en-us/library/aa384253%28v=vs.85%29.aspx
-# if !defined(KEY_WOW64_32KEY)
-# define KEY_WOW64_32KEY 0x0200
-# endif
-# if !defined(KEY_WOW64_64KEY)
-# define KEY_WOW64_64KEY 0x0100
-# endif
void cmFindPackageCommand::LoadPackageRegistryWinUser()
{
// HKEY_CURRENT_USER\\Software shares 32-bit and 64-bit views.
@@ -1704,7 +2052,8 @@ void cmFindPackageCommand::LoadPackageRegistryWinSystem()
}
}
-void cmFindPackageCommand::LoadPackageRegistryWin(bool user, unsigned int view,
+void cmFindPackageCommand::LoadPackageRegistryWin(const bool user,
+ const unsigned int view,
cmSearchPath& outPaths)
{
std::wstring key = L"Software\\Kitware\\CMake\\Packages\\";
@@ -1756,28 +2105,8 @@ void cmFindPackageCommand::LoadPackageRegistryWin(bool user, unsigned int view,
RegCloseKey(hKey);
}
}
-#else
-class cmFindPackageCommandHoldFile
-{
- const char* File;
-
-public:
- cmFindPackageCommandHoldFile(const char* f)
- : File(f)
- {
- }
- ~cmFindPackageCommandHoldFile()
- {
- if (this->File) {
- cmSystemTools::RemoveFile(this->File);
- }
- }
- cmFindPackageCommandHoldFile(const cmFindPackageCommandHoldFile&) = delete;
- cmFindPackageCommandHoldFile& operator=(
- const cmFindPackageCommandHoldFile&) = delete;
- void Release() { this->File = nullptr; }
-};
+#else
void cmFindPackageCommand::LoadPackageRegistryDir(std::string const& dir,
cmSearchPath& outPaths)
{
@@ -1877,7 +2206,7 @@ void cmFindPackageCommand::FillPrefixesCMakeSystemVariable()
std::vector<std::string> expanded = cmExpandedList(*prefix_paths);
long count = 0;
for (const auto& path : expanded) {
- bool to_add =
+ bool const to_add =
!(path == install_path_to_remove && ++count == install_prefix_count);
if (to_add) {
paths.AddPath(path);
@@ -1941,7 +2270,7 @@ bool cmFindPackageCommand::SearchDirectory(std::string const& dir)
std::string d = dir;
if (!s.empty()) {
d += s;
- d += "/";
+ d += '/';
}
if (this->CheckDirectory(d)) {
return true;
@@ -1955,7 +2284,7 @@ bool cmFindPackageCommand::CheckDirectory(std::string const& dir)
assert(!dir.empty() && dir.back() == '/');
// Look for the file in this directory.
- std::string d = dir.substr(0, dir.size() - 1);
+ std::string const d = dir.substr(0, dir.size() - 1);
if (this->FindConfigFile(d, this->FileFound)) {
// Remove duplicate slashes.
cmSystemTools::ConvertToUnixSlashes(this->FileFound);
@@ -2028,8 +2357,8 @@ bool cmFindPackageCommand::CheckVersionFile(std::string const& version_file,
std::string& result_version)
{
// The version file will be loaded in an isolated scope.
- cmMakefile::ScopePushPop varScope(this->Makefile);
- cmMakefile::PolicyPushPop polScope(this->Makefile);
+ cmMakefile::ScopePushPop const varScope(this->Makefile);
+ cmMakefile::PolicyPushPop const polScope(this->Makefile);
static_cast<void>(varScope);
static_cast<void>(polScope);
@@ -2076,7 +2405,7 @@ bool cmFindPackageCommand::CheckVersionFile(std::string const& version_file,
if (this->ReadListFile(version_file, NoPolicyScope)) {
// Check the output variables.
bool okay = this->Makefile->IsOn("PACKAGE_VERSION_EXACT");
- bool unsuitable = this->Makefile->IsOn("PACKAGE_VERSION_UNSUITABLE");
+ bool const unsuitable = this->Makefile->IsOn("PACKAGE_VERSION_UNSUITABLE");
if (!okay && !this->VersionExact) {
okay = this->Makefile->IsOn("PACKAGE_VERSION_COMPATIBLE");
}
@@ -2096,8 +2425,8 @@ bool cmFindPackageCommand::CheckVersionFile(std::string const& version_file,
unsigned int parsed_patch;
unsigned int parsed_tweak;
this->VersionFoundCount =
- sscanf(this->VersionFound.c_str(), "%u.%u.%u.%u", &parsed_major,
- &parsed_minor, &parsed_patch, &parsed_tweak);
+ parseVersion(this->VersionFound, parsed_major, parsed_minor,
+ parsed_patch, parsed_tweak);
switch (this->VersionFoundCount) {
case 4:
this->VersionFoundTweak = parsed_tweak;
@@ -2129,7 +2458,7 @@ bool cmFindPackageCommand::CheckVersionFile(std::string const& version_file,
void cmFindPackageCommand::StoreVersionFound()
{
// Store the whole version string.
- std::string ver = cmStrCat(this->Name, "_VERSION");
+ std::string const ver = cmStrCat(this->Name, "_VERSION");
auto addDefinition = [this](const std::string& variable,
cm::string_view value) {
this->Makefile->AddDefinition(variable, value);
@@ -2145,357 +2474,6 @@ void cmFindPackageCommand::StoreVersionFound()
}
}
-class cmFileListGeneratorBase
-{
-public:
- virtual ~cmFileListGeneratorBase() = default;
-
-protected:
- bool Consider(std::string const& fullPath, cmFileList& listing);
-
-private:
- bool Search(cmFileList&);
- virtual bool Search(std::string const& parent, cmFileList&) = 0;
- virtual std::unique_ptr<cmFileListGeneratorBase> Clone() const = 0;
- friend class cmFileList;
- cmFileListGeneratorBase* SetNext(cmFileListGeneratorBase const& next);
- std::unique_ptr<cmFileListGeneratorBase> Next;
-};
-
-class cmFileList
-{
-public:
- virtual ~cmFileList() = default;
- cmFileList& operator/(cmFileListGeneratorBase const& rhs)
- {
- if (this->Last) {
- this->Last = this->Last->SetNext(rhs);
- } else {
- this->First = rhs.Clone();
- this->Last = this->First.get();
- }
- return *this;
- }
- bool Search()
- {
- if (this->First) {
- return this->First->Search(*this);
- }
- return false;
- }
-
-private:
- virtual bool Visit(std::string const& fullPath) = 0;
- friend class cmFileListGeneratorBase;
- std::unique_ptr<cmFileListGeneratorBase> First;
- cmFileListGeneratorBase* Last = nullptr;
-};
-
-class cmFindPackageFileList : public cmFileList
-{
-public:
- cmFindPackageFileList(cmFindPackageCommand* fpc, bool use_suffixes = true)
- : FPC(fpc)
- , UseSuffixes(use_suffixes)
- {
- }
-
-private:
- bool Visit(std::string const& fullPath) override
- {
- if (this->UseSuffixes) {
- return this->FPC->SearchDirectory(fullPath);
- }
- return this->FPC->CheckDirectory(fullPath);
- }
- cmFindPackageCommand* FPC;
- bool UseSuffixes;
-};
-
-bool cmFileListGeneratorBase::Search(cmFileList& listing)
-{
- return this->Search("", listing);
-}
-
-cmFileListGeneratorBase* cmFileListGeneratorBase::SetNext(
- cmFileListGeneratorBase const& next)
-{
- this->Next = next.Clone();
- return this->Next.get();
-}
-
-bool cmFileListGeneratorBase::Consider(std::string const& fullPath,
- cmFileList& listing)
-{
- if (!fullPath.empty() && !cmSystemTools::FileIsDirectory(fullPath)) {
- return false;
- }
- if (this->Next) {
- return this->Next->Search(fullPath + "/", listing);
- }
- return listing.Visit(fullPath + "/");
-}
-
-class cmFileListGeneratorFixed : public cmFileListGeneratorBase
-{
-public:
- cmFileListGeneratorFixed(std::string str)
- : String(std::move(str))
- {
- }
- cmFileListGeneratorFixed(cmFileListGeneratorFixed const& r)
- : String(r.String)
- {
- }
-
-private:
- std::string String;
- bool Search(std::string const& parent, cmFileList& lister) override
- {
- std::string fullPath = parent + this->String;
- return this->Consider(fullPath, lister);
- }
- std::unique_ptr<cmFileListGeneratorBase> Clone() const override
- {
- std::unique_ptr<cmFileListGeneratorBase> g(
- new cmFileListGeneratorFixed(*this));
- return g;
- }
-};
-
-class cmFileListGeneratorEnumerate : public cmFileListGeneratorBase
-{
-public:
- cmFileListGeneratorEnumerate(std::vector<std::string> const& v)
- : Vector(v)
- {
- }
- cmFileListGeneratorEnumerate(cmFileListGeneratorEnumerate const& r)
- : Vector(r.Vector)
- {
- }
-
-private:
- std::vector<std::string> const& Vector;
- bool Search(std::string const& parent, cmFileList& lister) override
- {
- for (std::string const& i : this->Vector) {
- if (this->Consider(parent + i, lister)) {
- return true;
- }
- }
- return false;
- }
- std::unique_ptr<cmFileListGeneratorBase> Clone() const override
- {
- std::unique_ptr<cmFileListGeneratorBase> g(
- new cmFileListGeneratorEnumerate(*this));
- return g;
- }
-};
-
-class cmFileListGeneratorProject : public cmFileListGeneratorBase
-{
-public:
- cmFileListGeneratorProject(std::vector<std::string> const& names,
- cmFindPackageCommand::SortOrderType so,
- cmFindPackageCommand::SortDirectionType sd)
- : Names(names)
- {
- this->SetSort(so, sd);
- }
- cmFileListGeneratorProject(cmFileListGeneratorProject const& r)
- : Names(r.Names)
- {
- this->SetSort(r.SortOrder, r.SortDirection);
- }
-
- void SetSort(cmFindPackageCommand::SortOrderType o,
- cmFindPackageCommand::SortDirectionType d)
- {
- this->SortOrder = o;
- this->SortDirection = d;
- }
-
-protected:
- // sort parameters
- cmFindPackageCommand::SortOrderType SortOrder;
- cmFindPackageCommand::SortDirectionType SortDirection;
-
-private:
- std::vector<std::string> const& Names;
- bool Search(std::string const& parent, cmFileList& lister) override
- {
- // Construct a list of matches.
- std::vector<std::string> matches;
- cmsys::Directory d;
- d.Load(parent);
- for (unsigned long i = 0; i < d.GetNumberOfFiles(); ++i) {
- const char* fname = d.GetFile(i);
- if (strcmp(fname, ".") == 0 || strcmp(fname, "..") == 0) {
- continue;
- }
- for (std::string const& n : this->Names) {
- if (cmsysString_strncasecmp(fname, n.c_str(), n.length()) == 0) {
- matches.emplace_back(fname);
- }
- }
- }
-
- // before testing the matches check if there is a specific sorting order to
- // perform
- if (this->SortOrder != cmFindPackageCommand::None) {
- cmFindPackageCommand::Sort(matches.begin(), matches.end(),
- this->SortOrder, this->SortDirection);
- }
-
- for (std::string const& i : matches) {
- if (this->Consider(parent + i, lister)) {
- return true;
- }
- }
- return false;
- }
- std::unique_ptr<cmFileListGeneratorBase> Clone() const override
- {
- std::unique_ptr<cmFileListGeneratorBase> g(
- new cmFileListGeneratorProject(*this));
- return g;
- }
-};
-
-class cmFileListGeneratorMacProject : public cmFileListGeneratorBase
-{
-public:
- cmFileListGeneratorMacProject(std::vector<std::string> const& names,
- const char* ext)
- : Names(names)
- , Extension(ext)
- {
- }
- cmFileListGeneratorMacProject(cmFileListGeneratorMacProject const& r)
- : Names(r.Names)
- , Extension(r.Extension)
- {
- }
-
-private:
- std::vector<std::string> const& Names;
- std::string Extension;
- bool Search(std::string const& parent, cmFileList& lister) override
- {
- // Construct a list of matches.
- std::vector<std::string> matches;
- cmsys::Directory d;
- d.Load(parent);
- for (unsigned long i = 0; i < d.GetNumberOfFiles(); ++i) {
- const char* fname = d.GetFile(i);
- if (strcmp(fname, ".") == 0 || strcmp(fname, "..") == 0) {
- continue;
- }
- for (std::string name : this->Names) {
- name += this->Extension;
- if (cmsysString_strcasecmp(fname, name.c_str()) == 0) {
- matches.emplace_back(fname);
- }
- }
- }
-
- for (std::string const& i : matches) {
- if (this->Consider(parent + i, lister)) {
- return true;
- }
- }
- return false;
- }
- std::unique_ptr<cmFileListGeneratorBase> Clone() const override
- {
- std::unique_ptr<cmFileListGeneratorBase> g(
- new cmFileListGeneratorMacProject(*this));
- return g;
- }
-};
-
-class cmFileListGeneratorCaseInsensitive : public cmFileListGeneratorBase
-{
-public:
- cmFileListGeneratorCaseInsensitive(std::string str)
- : String(std::move(str))
- {
- }
- cmFileListGeneratorCaseInsensitive(
- cmFileListGeneratorCaseInsensitive const& r)
- : String(r.String)
- {
- }
-
-private:
- std::string String;
- bool Search(std::string const& parent, cmFileList& lister) override
- {
- // Look for matching files.
- std::vector<std::string> matches;
- cmsys::Directory d;
- d.Load(parent);
- for (unsigned long i = 0; i < d.GetNumberOfFiles(); ++i) {
- const char* fname = d.GetFile(i);
- if (strcmp(fname, ".") == 0 || strcmp(fname, "..") == 0) {
- continue;
- }
- if (cmsysString_strcasecmp(fname, this->String.c_str()) == 0) {
- if (this->Consider(parent + fname, lister)) {
- return true;
- }
- }
- }
- return false;
- }
- std::unique_ptr<cmFileListGeneratorBase> Clone() const override
- {
- std::unique_ptr<cmFileListGeneratorBase> g(
- new cmFileListGeneratorCaseInsensitive(*this));
- return g;
- }
-};
-
-class cmFileListGeneratorGlob : public cmFileListGeneratorBase
-{
-public:
- cmFileListGeneratorGlob(std::string str)
- : Pattern(std::move(str))
- {
- }
- cmFileListGeneratorGlob(cmFileListGeneratorGlob const& r)
- : Pattern(r.Pattern)
- {
- }
-
-private:
- std::string Pattern;
- bool Search(std::string const& parent, cmFileList& lister) override
- {
- // Glob the set of matching files.
- std::string expr = cmStrCat(parent, this->Pattern);
- cmsys::Glob g;
- if (!g.FindFiles(expr)) {
- return false;
- }
- std::vector<std::string> const& files = g.GetFiles();
-
- // Look for directories among the matches.
- for (std::string const& f : files) {
- if (this->Consider(f, lister)) {
- return true;
- }
- }
- return false;
- }
- std::unique_ptr<cmFileListGeneratorBase> Clone() const override
- {
- return cm::make_unique<cmFileListGeneratorGlob>(*this);
- }
-};
-
bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
{
assert(!prefix_in.empty() && prefix_in.back() == '/');
@@ -2515,148 +2493,101 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
return false;
}
- // PREFIX/ (useful on windows or in build trees)
+ // PREFIX/ (useful on windows or in build trees)
if (this->SearchDirectory(prefix_in)) {
return true;
}
// Strip the trailing slash because the path generator is about to
// add one.
- std::string prefix = prefix_in.substr(0, prefix_in.size() - 1);
+ std::string const prefix = prefix_in.substr(0, prefix_in.size() - 1);
- // PREFIX/(cmake|CMake)/ (useful on windows or in build trees)
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorCaseInsensitive("cmake");
- if (lister.Search()) {
- return true;
- }
+ auto searchFn = [this](const std::string& fullPath) -> bool {
+ return this->SearchDirectory(fullPath);
+ };
+
+ auto iCMakeGen = cmCaseInsensitiveDirectoryListGenerator{ "cmake"_s };
+ auto firstPkgDirGen =
+ cmProjectDirectoryListGenerator{ this->Names, this->SortOrder,
+ this->SortDirection };
+
+ // PREFIX/(cmake|CMake)/ (useful on windows or in build trees)
+ if (TryGeneratedPaths(searchFn, prefix, iCMakeGen)) {
+ return true;
}
- // PREFIX/(Foo|foo|FOO).*/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection);
- if (lister.Search()) {
- return true;
- }
+ // PREFIX/(Foo|foo|FOO).*/
+ if (TryGeneratedPaths(searchFn, prefix, firstPkgDirGen)) {
+ return true;
}
- // PREFIX/(Foo|foo|FOO).*/(cmake|CMake)/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection) /
- cmFileListGeneratorCaseInsensitive("cmake");
- if (lister.Search()) {
- return true;
- }
+ // PREFIX/(Foo|foo|FOO).*/(cmake|CMake)/
+ if (TryGeneratedPaths(searchFn, prefix, firstPkgDirGen, iCMakeGen)) {
+ return true;
+ }
+
+ auto secondPkgDirGen =
+ cmProjectDirectoryListGenerator{ this->Names, this->SortOrder,
+ this->SortDirection };
+
+ // PREFIX/(Foo|foo|FOO).*/(cmake|CMake)/(Foo|foo|FOO).*/
+ if (TryGeneratedPaths(searchFn, prefix, firstPkgDirGen, iCMakeGen,
+ secondPkgDirGen)) {
+ return true;
}
// Construct list of common install locations (lib and share).
- std::vector<std::string> common;
+ std::vector<cm::string_view> common;
+ std::string libArch;
if (!this->LibraryArchitecture.empty()) {
- common.push_back("lib/" + this->LibraryArchitecture);
+ libArch = "lib/" + this->LibraryArchitecture;
+ common.emplace_back(libArch);
}
if (this->UseLib32Paths) {
- common.emplace_back("lib32");
+ common.emplace_back("lib32"_s);
}
if (this->UseLib64Paths) {
- common.emplace_back("lib64");
+ common.emplace_back("lib64"_s);
}
if (this->UseLibx32Paths) {
- common.emplace_back("libx32");
+ common.emplace_back("libx32"_s);
}
- common.emplace_back("lib");
- common.emplace_back("share");
+ common.emplace_back("lib"_s);
+ common.emplace_back("share"_s);
- // PREFIX/(lib/ARCH|lib*|share)/cmake/(Foo|foo|FOO).*/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorEnumerate(common) /
- cmFileListGeneratorFixed("cmake") /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection);
- if (lister.Search()) {
- return true;
- }
+ auto cmnGen = cmEnumPathSegmentsGenerator{ common };
+ auto cmakeGen = cmAppendPathSegmentGenerator{ "cmake"_s };
+
+ // PREFIX/(lib/ARCH|lib*|share)/cmake/(Foo|foo|FOO).*/
+ if (TryGeneratedPaths(searchFn, prefix, cmnGen, cmakeGen, firstPkgDirGen)) {
+ return true;
}
- // PREFIX/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorEnumerate(common) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection);
- if (lister.Search()) {
- return true;
- }
+ // PREFIX/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/
+ if (TryGeneratedPaths(searchFn, prefix, cmnGen, firstPkgDirGen)) {
+ return true;
}
- // PREFIX/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/(cmake|CMake)/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorEnumerate(common) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection) /
- cmFileListGeneratorCaseInsensitive("cmake");
- if (lister.Search()) {
- return true;
- }
+ // PREFIX/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/(cmake|CMake)/
+ if (TryGeneratedPaths(searchFn, prefix, cmnGen, firstPkgDirGen, iCMakeGen)) {
+ return true;
}
// PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib*|share)/cmake/(Foo|foo|FOO).*/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection) /
- cmFileListGeneratorEnumerate(common) /
- cmFileListGeneratorFixed("cmake") /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection);
- if (lister.Search()) {
- return true;
- }
+ if (TryGeneratedPaths(searchFn, prefix, firstPkgDirGen, cmnGen, cmakeGen,
+ secondPkgDirGen)) {
+ return true;
}
// PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection) /
- cmFileListGeneratorEnumerate(common) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection);
- if (lister.Search()) {
- return true;
- }
+ if (TryGeneratedPaths(searchFn, prefix, firstPkgDirGen, cmnGen,
+ secondPkgDirGen)) {
+ return true;
}
// PREFIX/(Foo|foo|FOO).*/(lib/ARCH|lib*|share)/(Foo|foo|FOO).*/(cmake|CMake)/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection) /
- cmFileListGeneratorEnumerate(common) /
- cmFileListGeneratorProject(this->Names, this->SortOrder,
- this->SortDirection) /
- cmFileListGeneratorCaseInsensitive("cmake");
- if (lister.Search()) {
- return true;
- }
- }
-
- return false;
+ return TryGeneratedPaths(searchFn, prefix, firstPkgDirGen, cmnGen,
+ secondPkgDirGen, iCMakeGen);
}
bool cmFindPackageCommand::SearchFrameworkPrefix(std::string const& prefix_in)
@@ -2665,56 +2596,36 @@ bool cmFindPackageCommand::SearchFrameworkPrefix(std::string const& prefix_in)
// Strip the trailing slash because the path generator is about to
// add one.
- std::string prefix = prefix_in.substr(0, prefix_in.size() - 1);
+ std::string const prefix = prefix_in.substr(0, prefix_in.size() - 1);
+
+ auto searchFn = [this](const std::string& fullPath) -> bool {
+ return this->SearchDirectory(fullPath);
+ };
+
+ auto iCMakeGen = cmCaseInsensitiveDirectoryListGenerator{ "cmake"_s };
+ auto fwGen =
+ cmMacProjectDirectoryListGenerator{ this->Names, ".framework"_s };
+ auto rGen = cmAppendPathSegmentGenerator{ "Resources"_s };
+ auto vGen = cmAppendPathSegmentGenerator{ "Versions"_s };
+ auto grGen = cmFileListGeneratorGlob{ "/*/Resources"_s };
// <prefix>/Foo.framework/Resources/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorMacProject(this->Names, ".framework") /
- cmFileListGeneratorFixed("Resources");
- if (lister.Search()) {
- return true;
- }
+ if (TryGeneratedPaths(searchFn, prefix, fwGen, rGen)) {
+ return true;
}
+
// <prefix>/Foo.framework/Resources/CMake/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorMacProject(this->Names, ".framework") /
- cmFileListGeneratorFixed("Resources") /
- cmFileListGeneratorCaseInsensitive("cmake");
- if (lister.Search()) {
- return true;
- }
+ if (TryGeneratedPaths(searchFn, prefix, fwGen, rGen, iCMakeGen)) {
+ return true;
}
// <prefix>/Foo.framework/Versions/*/Resources/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorMacProject(this->Names, ".framework") /
- cmFileListGeneratorFixed("Versions") /
- cmFileListGeneratorGlob("*/Resources");
- if (lister.Search()) {
- return true;
- }
+ if (TryGeneratedPaths(searchFn, prefix, fwGen, vGen, grGen)) {
+ return true;
}
// <prefix>/Foo.framework/Versions/*/Resources/CMake/
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorMacProject(this->Names, ".framework") /
- cmFileListGeneratorFixed("Versions") /
- cmFileListGeneratorGlob("*/Resources") /
- cmFileListGeneratorCaseInsensitive("cmake");
- if (lister.Search()) {
- return true;
- }
- }
-
- return false;
+ return TryGeneratedPaths(searchFn, prefix, fwGen, vGen, grGen, iCMakeGen);
}
bool cmFindPackageCommand::SearchAppBundlePrefix(std::string const& prefix_in)
@@ -2723,32 +2634,24 @@ bool cmFindPackageCommand::SearchAppBundlePrefix(std::string const& prefix_in)
// Strip the trailing slash because the path generator is about to
// add one.
- std::string prefix = prefix_in.substr(0, prefix_in.size() - 1);
+ std::string const prefix = prefix_in.substr(0, prefix_in.size() - 1);
+
+ auto searchFn = [this](const std::string& fullPath) -> bool {
+ return this->SearchDirectory(fullPath);
+ };
+
+ auto appGen = cmMacProjectDirectoryListGenerator{ this->Names, ".app"_s };
+ auto crGen = cmAppendPathSegmentGenerator{ "Contents/Resources"_s };
// <prefix>/Foo.app/Contents/Resources
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorMacProject(this->Names, ".app") /
- cmFileListGeneratorFixed("Contents/Resources");
- if (lister.Search()) {
- return true;
- }
+ if (TryGeneratedPaths(searchFn, prefix, appGen, crGen)) {
+ return true;
}
// <prefix>/Foo.app/Contents/Resources/CMake
- {
- cmFindPackageFileList lister(this);
- lister / cmFileListGeneratorFixed(prefix) /
- cmFileListGeneratorMacProject(this->Names, ".app") /
- cmFileListGeneratorFixed("Contents/Resources") /
- cmFileListGeneratorCaseInsensitive("cmake");
- if (lister.Search()) {
- return true;
- }
- }
-
- return false;
+ return TryGeneratedPaths(
+ searchFn, prefix, appGen, crGen,
+ cmCaseInsensitiveDirectoryListGenerator{ "cmake"_s });
}
// TODO: Debug cmsys::Glob double slash problem.
diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h
index 80fd8f8..28e00a1 100644
--- a/Source/cmFindPackageCommand.h
+++ b/Source/cmFindPackageCommand.h
@@ -153,8 +153,6 @@ private:
bool SearchFrameworkPrefix(std::string const& prefix_in);
bool SearchAppBundlePrefix(std::string const& prefix_in);
- friend class cmFindPackageFileList;
-
struct OriginalDef
{
bool exists;
diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx
index b9400c9..3465c23 100644
--- a/Source/cmForEachCommand.cxx
+++ b/Source/cmForEachCommand.cxx
@@ -260,7 +260,7 @@ auto cmForEachFunctionBlocker::invoke(
cmExecutionStatus status(mf);
mf.ExecuteCommand(func, status);
if (status.GetReturnInvoked()) {
- inStatus.SetReturnInvoked();
+ inStatus.SetReturnInvoked(status.GetReturnVariables());
result.Break = true;
break;
}
diff --git a/Source/cmFunctionBlocker.cxx b/Source/cmFunctionBlocker.cxx
index 40e692d..523482a 100644
--- a/Source/cmFunctionBlocker.cxx
+++ b/Source/cmFunctionBlocker.cxx
@@ -24,10 +24,11 @@ bool cmFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
auto self = mf.RemoveFunctionBlocker();
assert(self.get() == this);
- if (!this->ArgumentsMatch(lff, mf)) {
- cmListFileContext const& lfc = this->GetStartingContext();
- cmListFileContext closingContext =
- cmListFileContext::FromListFileFunction(lff, lfc.FilePath);
+ cmListFileContext const& lfc = this->GetStartingContext();
+ cmListFileContext closingContext =
+ cmListFileContext::FromListFileFunction(lff, lfc.FilePath);
+ if (this->EndCommandSupportsArguments() &&
+ !this->ArgumentsMatch(lff, mf)) {
std::ostringstream e;
/* clang-format off */
e << "A logical block opening on the line\n"
@@ -37,6 +38,15 @@ bool cmFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
<< "with mis-matching arguments.";
/* clang-format on */
mf.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
+ } else if (!this->EndCommandSupportsArguments() &&
+ !lff.Arguments().empty()) {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "A logical block closing on the line\n"
+ " " << closingContext << "\n"
+ "has unexpected arguments.";
+ /* clang-format on */
+ mf.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
}
return this->Replay(std::move(this->Functions), status);
diff --git a/Source/cmFunctionBlocker.h b/Source/cmFunctionBlocker.h
index 38abeba..3e096f2 100644
--- a/Source/cmFunctionBlocker.h
+++ b/Source/cmFunctionBlocker.h
@@ -38,6 +38,8 @@ private:
virtual cm::string_view StartCommandName() const = 0;
virtual cm::string_view EndCommandName() const = 0;
+ virtual bool EndCommandSupportsArguments() const { return true; }
+
virtual bool ArgumentsMatch(cmListFileFunction const& lff,
cmMakefile& mf) const = 0;
diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx
index 1359009..f4768b6 100644
--- a/Source/cmFunctionCommand.cxx
+++ b/Source/cmFunctionCommand.cxx
@@ -120,6 +120,7 @@ bool cmFunctionHelperCommand::operator()(
return false;
}
if (status.GetReturnInvoked()) {
+ makefile.RaiseScope(status.GetReturnVariables());
break;
}
}
diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx
index b529b8f..6212bbd 100644
--- a/Source/cmGeneratedFileStream.cxx
+++ b/Source/cmGeneratedFileStream.cxx
@@ -124,10 +124,10 @@ cmGeneratedFileStreamBase::~cmGeneratedFileStreamBase()
void cmGeneratedFileStreamBase::Open(std::string const& name)
{
// Save the original name of the file.
- this->Name = name;
+ this->Name = cmSystemTools::CollapseFullPath(name);
// Create the name of the temporary file.
- this->TempName = name;
+ this->TempName = this->Name;
#if defined(__VMS)
this->TempName += "_";
#else
@@ -231,7 +231,7 @@ int cmGeneratedFileStreamBase::RenameFile(std::string const& oldname,
void cmGeneratedFileStream::SetName(const std::string& fname)
{
- this->Name = fname;
+ this->Name = cmSystemTools::CollapseFullPath(fname);
}
void cmGeneratedFileStream::SetTempExt(std::string const& ext)
diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx
index d35d428..6be5153 100644
--- a/Source/cmGeneratorExpressionDAGChecker.cxx
+++ b/Source/cmGeneratorExpressionDAGChecker.cxx
@@ -178,7 +178,7 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkOptionsExpression() const
}
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(
- cmGeneratorTarget const* tgt) const
+ cmGeneratorTarget const* tgt, ForGenex genex) const
{
const auto* top = this->Top();
@@ -188,13 +188,17 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(
return top->Target == tgt && prop == "LINK_LIBRARIES"_s;
}
- return prop == "LINK_LIBRARIES"_s || prop == "INTERFACE_LINK_LIBRARIES"_s ||
+ auto result = prop == "LINK_LIBRARIES"_s ||
+ prop == "INTERFACE_LINK_LIBRARIES"_s ||
prop == "INTERFACE_LINK_LIBRARIES_DIRECT"_s ||
- prop == "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"_s ||
prop == "LINK_INTERFACE_LIBRARIES"_s ||
prop == "IMPORTED_LINK_INTERFACE_LIBRARIES"_s ||
cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES_") ||
cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_");
+
+ return genex == ForGenex::LINK_LIBRARY || genex == ForGenex::LINK_GROUP
+ ? result
+ : (result || prop == "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"_s);
}
cmGeneratorExpressionDAGChecker const* cmGeneratorExpressionDAGChecker::Top()
diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h
index 93b44db..55d131f 100644
--- a/Source/cmGeneratorExpressionDAGChecker.h
+++ b/Source/cmGeneratorExpressionDAGChecker.h
@@ -71,7 +71,14 @@ struct cmGeneratorExpressionDAGChecker
bool EvaluatingLinkExpression() const;
bool EvaluatingLinkOptionsExpression() const;
- bool EvaluatingLinkLibraries(cmGeneratorTarget const* tgt = nullptr) const;
+ enum class ForGenex
+ {
+ ANY,
+ LINK_LIBRARY,
+ LINK_GROUP
+ };
+ bool EvaluatingLinkLibraries(cmGeneratorTarget const* tgt = nullptr,
+ ForGenex genex = ForGenex::ANY) const;
#define DECLARE_TRANSITIVE_PROPERTY_METHOD(METHOD) bool METHOD() const;
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index b08cddb..45d5a83 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -1662,11 +1662,16 @@ static const struct LinkLibraryNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* dagChecker) const override
{
+ using ForGenex = cmGeneratorExpressionDAGChecker::ForGenex;
+
if (!context->HeadTarget || !dagChecker ||
- !dagChecker->EvaluatingLinkLibraries()) {
+ !dagChecker->EvaluatingLinkLibraries(nullptr,
+ ForGenex::LINK_LIBRARY)) {
reportError(context, content->GetOriginalExpression(),
"$<LINK_LIBRARY:...> may only be used with binary targets "
- "to specify link libraries.");
+ "to specify link libraries through 'LINK_LIBRARIES', "
+ "'INTERFACE_LINK_LIBRARIES', and "
+ "'INTERFACE_LINK_LIBRARIES_DIRECT' properties.");
return std::string();
}
@@ -1743,11 +1748,16 @@ static const struct LinkGroupNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* dagChecker) const override
{
+ using ForGenex = cmGeneratorExpressionDAGChecker::ForGenex;
+
if (!context->HeadTarget || !dagChecker ||
- !dagChecker->EvaluatingLinkLibraries()) {
- reportError(context, content->GetOriginalExpression(),
- "$<LINK_GROUP:...> may only be used with binary targets "
- "to specify group of link libraries.");
+ !dagChecker->EvaluatingLinkLibraries(nullptr, ForGenex::LINK_GROUP)) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<LINK_GROUP:...> may only be used with binary targets "
+ "to specify group of link libraries through 'LINK_LIBRARIES', "
+ "'INTERFACE_LINK_LIBRARIES', and "
+ "'INTERFACE_LINK_LIBRARIES_DIRECT' properties.");
return std::string();
}
@@ -2763,8 +2773,18 @@ struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirNameTag>
return std::string();
}
- return target->GetAppBundleDirectory(context->Config,
- cmGeneratorTarget::BundleDirLevel);
+ auto level = cmGeneratorTarget::BundleDirLevel;
+ auto config = context->Config;
+ if (target->IsAppBundleOnApple()) {
+ return target->GetAppBundleDirectory(config, level);
+ }
+ if (target->IsFrameworkOnApple()) {
+ return target->GetFrameworkDirectory(config, level);
+ }
+ if (target->IsCFBundleOnApple()) {
+ return target->GetCFBundleDirectory(config, level);
+ }
+ return std::string();
}
};
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 433c1d5..7f1e426 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -16,6 +16,7 @@
#include <utility>
#include <cm/memory>
+#include <cm/optional>
#include <cm/string_view>
#include <cmext/algorithm>
#include <cmext/string_view>
@@ -916,11 +917,19 @@ bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang,
return false;
}
- if (lang != "C" && lang != "CXX" && lang != "Fortran") {
+ if (lang != "C" && lang != "CXX" && lang != "CUDA" && lang != "Fortran") {
// We do not define IPO behavior for other languages.
return false;
}
+ if (lang == "CUDA") {
+ // CUDA IPO requires both CUDA_ARCHITECTURES and CUDA_SEPARABLE_COMPILATION
+ if (cmIsOff(this->GetSafeProperty("CUDA_ARCHITECTURES")) ||
+ cmIsOff(this->GetSafeProperty("CUDA_SEPARABLE_COMPILATION"))) {
+ return false;
+ }
+ }
+
cmPolicies::PolicyStatus cmp0069 = this->GetPolicyStatusCMP0069();
if (cmp0069 == cmPolicies::OLD || cmp0069 == cmPolicies::WARN) {
@@ -1706,7 +1715,7 @@ void addFileSetEntry(cmGeneratorTarget const* headTarget,
}
bool found = false;
for (auto const& sg : headTarget->Makefile->GetSourceGroups()) {
- if (sg.MatchesFiles(path)) {
+ if (sg.MatchChildrenFiles(path)) {
found = true;
break;
}
@@ -3428,7 +3437,9 @@ void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags,
"EXPLICIT_LANGUAGE");
}
-void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
+void cmGeneratorTarget::AddCUDAArchitectureFlags(cmBuildStep compileOrLink,
+ const std::string& config,
+ std::string& flags) const
{
std::string property = this->GetSafeProperty("CUDA_ARCHITECTURES");
@@ -3460,6 +3471,7 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
std::string const& compiler =
this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID");
+ const bool ipoEnabled = this->IsIPOEnabled("CUDA", config);
// Check for special modes: `all`, `all-major`.
if (property == "all" || property == "all-major") {
@@ -3539,6 +3551,13 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
}
if (compiler == "NVIDIA") {
+ if (ipoEnabled && compileOrLink == cmBuildStep::Link) {
+ if (cmValue cudaIPOFlags =
+ this->Makefile->GetDefinition("CMAKE_CUDA_LINK_OPTIONS_IPO")) {
+ flags += cudaIPOFlags;
+ }
+ }
+
for (CudaArchitecture& architecture : architectures) {
flags +=
" --generate-code=arch=compute_" + architecture.name + ",code=[";
@@ -3551,7 +3570,13 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
}
}
- if (architecture.real) {
+ if (ipoEnabled) {
+ if (compileOrLink == cmBuildStep::Compile) {
+ flags += "lto_" + architecture.name;
+ } else if (compileOrLink == cmBuildStep::Link) {
+ flags += "sm_" + architecture.name;
+ }
+ } else if (architecture.real) {
flags += "sm_" + architecture.name;
}
@@ -8554,6 +8579,9 @@ bool cmGeneratorTarget::AddHeaderSetVerification()
}
cmTarget* verifyTarget = nullptr;
+ cmTarget* allVerifyTarget =
+ this->GlobalGenerator->GetMakefiles().front()->FindTargetToUse(
+ "all_verify_interface_header_sets", true);
auto interfaceFileSetEntries = this->Target->GetInterfaceHeaderSetsEntries();
@@ -8636,6 +8664,20 @@ bool cmGeneratorTarget::AddHeaderSetVerification()
verifyTarget->SetProperty("AUTOUIC", "OFF");
verifyTarget->SetProperty("DISABLE_PRECOMPILE_HEADERS", "ON");
verifyTarget->SetProperty("UNITY_BUILD", "OFF");
+ cm::optional<std::map<std::string, cmValue>>
+ perConfigCompileDefinitions;
+ verifyTarget->FinalizeTargetConfiguration(
+ this->Makefile->GetCompileDefinitionsEntries(),
+ perConfigCompileDefinitions);
+
+ if (!allVerifyTarget) {
+ allVerifyTarget = this->GlobalGenerator->GetMakefiles()
+ .front()
+ ->AddNewUtilityTarget(
+ "all_verify_interface_header_sets", true);
+ }
+
+ allVerifyTarget->AddUtility(verifyTarget->GetName(), false);
}
if (fileCgesContextSensitive) {
@@ -8682,6 +8724,12 @@ std::string cmGeneratorTarget::GenerateHeaderSetVerificationFile(
languages->insert("C");
}
}
+
+ if (languages->empty()) {
+ std::vector<std::string> languagesVector;
+ this->GlobalGenerator->GetEnabledLanguages(languagesVector);
+ languages->insert(languagesVector.begin(), languagesVector.end());
+ }
}
if (languages->count("CXX")) {
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 349afa7..25e6a81 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -23,6 +23,7 @@
#include "cmStateTypes.h"
#include "cmValue.h"
+enum class cmBuildStep;
class cmComputeLinkInformation;
class cmCustomCommand;
class cmGlobalGenerator;
@@ -471,7 +472,9 @@ public:
void AddExplicitLanguageFlags(std::string& flags,
cmSourceFile const& sf) const;
- void AddCUDAArchitectureFlags(std::string& flags) const;
+ void AddCUDAArchitectureFlags(cmBuildStep compileOrLink,
+ const std::string& config,
+ std::string& flags) const;
void AddCUDAToolkitFlags(std::string& flags) const;
void AddHIPArchitectureFlags(std::string& flags) const;
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index bf019c3..138d3f1 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -183,8 +183,8 @@ void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config,
auto i = this->FlagsByLanguage.find(language);
if (i == this->FlagsByLanguage.end()) {
std::string flags;
- this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
- language, config);
+ this->LocalGenerator->AddLanguageFlags(
+ flags, this->GeneratorTarget, cmBuildStep::Compile, language, config);
this->LocalGenerator->AddCMP0018Flags(flags, this->GeneratorTarget,
language, config);
this->LocalGenerator->AddVisibilityPresetFlags(
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 4cb541a..6962b52 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -14,6 +14,7 @@
#include <utility>
#include <cm/memory>
+#include <cm/optional>
#include <cmext/algorithm>
#include <cmext/string_view>
@@ -49,6 +50,8 @@
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
#include "cmValue.h"
#include "cmVersion.h"
#include "cmWorkingDirectory.h"
@@ -62,10 +65,6 @@
# include "cmQtAutoGenGlobalInitializer.h"
#endif
-#if defined(_MSC_VER) && _MSC_VER >= 1800
-# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-#endif
-
const std::string kCMAKE_PLATFORM_INFO_INITIALIZED =
"CMAKE_PLATFORM_INFO_INITIALIZED";
@@ -616,34 +615,12 @@ void cmGlobalGenerator::EnableLanguage(
// what platform we are running on
if (!mf->GetDefinition("CMAKE_SYSTEM")) {
#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Windows version number data. */
- OSVERSIONINFOEXW osviex;
- ZeroMemory(&osviex, sizeof(osviex));
- osviex.dwOSVersionInfoSize = sizeof(osviex);
-
-# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-# pragma warning(push)
-# ifdef __INTEL_COMPILER
-# pragma warning(disable : 1478)
-# elif defined __clang__
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wdeprecated-declarations"
-# else
-# pragma warning(disable : 4996)
-# endif
-# endif
- GetVersionExW((OSVERSIONINFOW*)&osviex);
-# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-# ifdef __clang__
-# pragma clang diagnostic pop
-# else
-# pragma warning(pop)
-# endif
-# endif
+ cmSystemTools::WindowsVersion windowsVersion =
+ cmSystemTools::GetWindowsVersion();
std::ostringstream windowsVersionString;
- windowsVersionString << osviex.dwMajorVersion << "."
- << osviex.dwMinorVersion << "."
- << osviex.dwBuildNumber;
+ windowsVersionString << windowsVersion.dwMajorVersion << "."
+ << windowsVersion.dwMinorVersion << "."
+ << windowsVersion.dwBuildNumber;
mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION", windowsVersionString.str());
#endif
// Read the DetermineSystem file
@@ -1399,7 +1376,9 @@ void cmGlobalGenerator::CreateGenerationObjects(TargetTypes targetTypes)
this->CheckTargetProperties();
}
this->CreateGeneratorTargets(targetTypes);
- this->ComputeBuildFileGenerators();
+ if (targetTypes == TargetTypes::AllTargets) {
+ this->ComputeBuildFileGenerators();
+ }
}
void cmGlobalGenerator::CreateImportedGenerationObjects(
@@ -1523,7 +1502,7 @@ bool cmGlobalGenerator::Compute()
if (!this->CheckALLOW_DUPLICATE_CUSTOM_TARGETS()) {
return false;
}
- this->FinalizeTargetCompileInfo();
+ this->FinalizeTargetConfiguration();
this->CreateGenerationObjects();
@@ -1780,6 +1759,14 @@ bool cmGlobalGenerator::AddHeaderSetVerification()
}
}
+ cmTarget* allVerifyTarget = this->Makefiles.front()->FindTargetToUse(
+ "all_verify_interface_header_sets", true);
+ if (allVerifyTarget) {
+ this->LocalGenerators.front()->AddGeneratorTarget(
+ cm::make_unique<cmGeneratorTarget>(allVerifyTarget,
+ this->LocalGenerators.front().get()));
+ }
+
return true;
}
@@ -1839,46 +1826,21 @@ cmGlobalGenerator::CreateMSVC60LinkLineComputer(
cm::make_unique<cmMSVC60LinkLineComputer>(outputConverter, stateDir));
}
-void cmGlobalGenerator::FinalizeTargetCompileInfo()
+void cmGlobalGenerator::FinalizeTargetConfiguration()
{
std::vector<std::string> const langs =
this->CMakeInstance->GetState()->GetEnabledLanguages();
// Construct per-target generator information.
for (const auto& mf : this->Makefiles) {
- const cmBTStringRange noconfig_compile_definitions =
+ const cmBTStringRange noConfigCompileDefinitions =
mf->GetCompileDefinitionsEntries();
+ cm::optional<std::map<std::string, cmValue>> perConfigCompileDefinitions;
for (auto& target : mf->GetTargets()) {
cmTarget* t = &target.second;
- if (t->GetType() == cmStateEnums::GLOBAL_TARGET) {
- continue;
- }
-
- t->AppendBuildInterfaceIncludes();
-
- if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
- continue;
- }
-
- for (auto const& def : noconfig_compile_definitions) {
- t->InsertCompileDefinition(def);
- }
-
- cmPolicies::PolicyStatus polSt =
- mf->GetPolicyStatus(cmPolicies::CMP0043);
- if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
- std::vector<std::string> configs =
- mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
-
- for (std::string const& c : configs) {
- std::string defPropName =
- cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(c));
- if (cmValue val = mf->GetProperty(defPropName)) {
- t->AppendProperty(defPropName, *val);
- }
- }
- }
+ t->FinalizeTargetConfiguration(noConfigCompileDefinitions,
+ perConfigCompileDefinitions);
}
// The standard include directories for each language
@@ -1893,6 +1855,15 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo()
cmExpandedList(standardIncludesStr);
standardIncludesSet.insert(standardIncludesVec.begin(),
standardIncludesVec.end());
+ if (li == "CUDA") {
+ std::string const& cudaSystemIncludeVar =
+ mf->GetSafeDefinition("CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES");
+ std::vector<std::string> cudaToolkitIncludeVec =
+ cmExpandedList(cudaSystemIncludeVar);
+ standardIncludesSet.insert(cudaToolkitIncludeVec.begin(),
+ cudaToolkitIncludeVec.end());
+ mf->AddIncludeDirectories(cudaToolkitIncludeVec);
+ }
}
mf->AddSystemIncludeDirectories(standardIncludesSet);
}
@@ -2592,9 +2563,9 @@ bool cmGlobalGenerator::NameResolvesToFramework(
// This is where we change the path to point to the framework directory.
// .tbd files also can be located in SDK frameworks (they are
// placeholders for actual libraries shipped with the OS)
-cm::optional<std::pair<std::string, std::string>>
+cm::optional<cmGlobalGenerator::FrameworkDescriptor>
cmGlobalGenerator::SplitFrameworkPath(const std::string& path,
- bool extendedFormat) const
+ FrameworkFormat format) const
{
// Check for framework structure:
// (/path/to/)?FwName.framework
@@ -2609,20 +2580,29 @@ cmGlobalGenerator::SplitFrameworkPath(const std::string& path,
auto name = frameworkPath.match(3);
auto libname =
cmSystemTools::GetFilenameWithoutExtension(frameworkPath.match(6));
- if (!libname.empty() && name != libname) {
+ if (format == FrameworkFormat::Strict && libname.empty()) {
return cm::nullopt;
}
- return std::pair<std::string, std::string>{ frameworkPath.match(2), name };
+ if (!libname.empty() && !cmHasPrefix(libname, name)) {
+ return cm::nullopt;
+ }
+
+ if (libname.empty() || name.size() == libname.size()) {
+ return FrameworkDescriptor{ frameworkPath.match(2), name };
+ }
+
+ return FrameworkDescriptor{ frameworkPath.match(2), name,
+ libname.substr(name.size()) };
}
- if (extendedFormat) {
+ if (format == FrameworkFormat::Extended) {
// path format can be more flexible: (/path/to/)?fwName(.framework)?
auto fwDir = cmSystemTools::GetParentDirectory(path);
auto name = cmSystemTools::GetFilenameLastExtension(path) == ".framework"
? cmSystemTools::GetFilenameWithoutExtension(path)
: cmSystemTools::GetFilenameName(path);
- return std::pair<std::string, std::string>{ fwDir, name };
+ return FrameworkDescriptor{ fwDir, name };
}
return cm::nullopt;
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index dcef070..89b2ea8 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -17,6 +17,7 @@
#include <cm/optional>
#include <cmext/algorithm>
+#include <cmext/string_view>
#include "cm_codecvt.hxx"
@@ -367,13 +368,61 @@ public:
/** Determine if a name resolves to a framework on disk or a built target
that is a framework. */
bool NameResolvesToFramework(const std::string& libname) const;
- /** Split a framework path to the directory and name of the framework
- * returns std::nullopt if the path does not match with framework format
+ /** Split a framework path to the directory and name of the framework as well
+ * as optiona; suffix.
+ * Returns std::nullopt if the path does not match with framework format
* when extendedFormat is true, required format is relaxed (i.e. extension
* `.framework' is optional). Used when FRAMEWORK link feature is
* specified */
- cm::optional<std::pair<std::string, std::string>> SplitFrameworkPath(
- const std::string& path, bool extendedFormat = false) const;
+ struct FrameworkDescriptor
+ {
+ FrameworkDescriptor(std::string directory, std::string name)
+ : Directory(std::move(directory))
+ , Name(std::move(name))
+ {
+ }
+ FrameworkDescriptor(std::string directory, std::string name,
+ std::string suffix)
+ : Directory(std::move(directory))
+ , Name(std::move(name))
+ , Suffix(std::move(suffix))
+ {
+ }
+ std::string GetLinkName() const
+ {
+ return this->Suffix.empty() ? this->Name
+ : cmStrCat(this->Name, ',', this->Suffix);
+ }
+ std::string GetFullName() const
+ {
+ return cmStrCat(this->Name, ".framework/"_s, this->Name, this->Suffix);
+ }
+ std::string GetFrameworkPath() const
+ {
+ return this->Directory.empty()
+ ? cmStrCat(this->Name, ".framework"_s)
+ : cmStrCat(this->Directory, '/', this->Name, ".framework"_s);
+ }
+ std::string GetFullPath() const
+ {
+ return this->Directory.empty()
+ ? this->GetFullName()
+ : cmStrCat(this->Directory, '/', this->GetFullName());
+ }
+
+ const std::string Directory;
+ const std::string Name;
+ const std::string Suffix;
+ };
+ enum class FrameworkFormat
+ {
+ Strict,
+ Relaxed,
+ Extended
+ };
+ cm::optional<FrameworkDescriptor> SplitFrameworkPath(
+ const std::string& path,
+ FrameworkFormat format = FrameworkFormat::Relaxed) const;
cmMakefile* FindMakefile(const std::string& start_dir) const;
cmLocalGenerator* FindLocalGenerator(cmDirectoryId const& id) const;
@@ -694,7 +743,7 @@ private:
void WriteSummary();
void WriteSummary(cmGeneratorTarget* target);
- void FinalizeTargetCompileInfo();
+ void FinalizeTargetConfiguration();
virtual void ForceLinkerLanguages();
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 7cbe80a..c326ca6 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -3,6 +3,7 @@
#include "cmGlobalNinjaGenerator.h"
#include <algorithm>
+#include <cassert>
#include <cctype>
#include <cstdio>
#include <functional>
@@ -15,6 +16,7 @@
#include <cm/string_view>
#include <cmext/algorithm>
#include <cmext/memory>
+#include <cmext/string_view>
#include <cm3p/json/reader.h>
#include <cm3p/json/value.h>
@@ -24,6 +26,7 @@
#include "cmCxxModuleMapper.h"
#include "cmDocumentationEntry.h"
+#include "cmFileSet.h"
#include "cmFortranParser.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpressionEvaluationFile.h"
@@ -2482,13 +2485,53 @@ cm::optional<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
}
}
+struct CxxModuleFileSet
+{
+ std::string Name;
+ std::string RelativeDirectory;
+ std::string SourcePath;
+ std::string Type;
+ cmFileSetVisibility Visibility;
+ cm::optional<std::string> Destination;
+};
+
+struct CxxModuleBmiInstall
+{
+ std::string Component;
+ std::string Destination;
+ bool ExcludeFromAll;
+ bool Optional;
+ std::string Permissions;
+ std::string MessageLevel;
+ std::string ScriptLocation;
+};
+
+struct CxxModuleExport
+{
+ std::string Name;
+ std::string Destination;
+ std::string Prefix;
+ std::string CxxModuleInfoDir;
+ std::string Namespace;
+ bool Install;
+};
+
+struct cmGlobalNinjaGenerator::CxxModuleExportInfo
+{
+ std::map<std::string, CxxModuleFileSet> ObjectToFileSet;
+ cm::optional<CxxModuleBmiInstall> BmiInstallation;
+ std::vector<CxxModuleExport> Exports;
+ std::string Config;
+};
+
bool cmGlobalNinjaGenerator::WriteDyndepFile(
std::string const& dir_top_src, std::string const& dir_top_bld,
std::string const& dir_cur_src, std::string const& dir_cur_bld,
std::string const& arg_dd, std::vector<std::string> const& arg_ddis,
std::string const& module_dir,
std::vector<std::string> const& linked_target_dirs,
- std::string const& arg_lang, std::string const& arg_modmapfmt)
+ std::string const& arg_lang, std::string const& arg_modmapfmt,
+ CxxModuleExportInfo const& export_info)
{
// Setup path conversions.
{
@@ -2513,6 +2556,8 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
objects.push_back(std::move(info));
}
+ CxxModuleUsage usages;
+
// Map from module name to module file path, if known.
std::map<std::string, std::string> mod_files;
@@ -2530,8 +2575,47 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
return false;
}
if (ltm.isObject()) {
- for (Json::Value::iterator i = ltm.begin(); i != ltm.end(); ++i) {
- mod_files[i.key().asString()] = i->asString();
+ Json::Value const& target_modules = ltm["modules"];
+ if (target_modules.isObject()) {
+ for (auto i = target_modules.begin(); i != target_modules.end(); ++i) {
+ mod_files[i.key().asString()] = i->asString();
+ }
+ }
+ Json::Value const& target_modules_references = ltm["references"];
+ if (target_modules_references.isObject()) {
+ for (auto i = target_modules_references.begin();
+ i != target_modules_references.end(); ++i) {
+ if (i->isObject()) {
+ Json::Value const& reference_path = (*i)["path"];
+ CxxModuleReference module_reference;
+ if (reference_path.isString()) {
+ module_reference.Path = reference_path.asString();
+ }
+ Json::Value const& reference_method = (*i)["lookup-method"];
+ if (reference_method.isString()) {
+ std::string reference = reference_method.asString();
+ if (reference == "by-name") {
+ module_reference.Method = LookupMethod::ByName;
+ } else if (reference == "include-angle") {
+ module_reference.Method = LookupMethod::IncludeAngle;
+ } else if (reference == "include-quote") {
+ module_reference.Method = LookupMethod::IncludeQuote;
+ }
+ }
+ usages.Reference[i.key().asString()] = module_reference;
+ }
+ }
+ }
+ Json::Value const& target_modules_usage = ltm["usages"];
+ if (target_modules_usage.isObject()) {
+ for (auto i = target_modules_usage.begin();
+ i != target_modules_usage.end(); ++i) {
+ if (i->isArray()) {
+ for (auto j = i->begin(); j != i->end(); ++j) {
+ usages.Usage[i.key().asString()].insert(j->asString());
+ }
+ }
+ }
}
}
}
@@ -2541,6 +2625,8 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
// nothing to do.
} else if (arg_modmapfmt == "gcc") {
modmap_fmt = CxxModuleMapFormat::Gcc;
+ } else if (arg_modmapfmt == "msvc") {
+ modmap_fmt = CxxModuleMapFormat::Msvc;
} else {
cmSystemTools::Error(
cmStrCat("-E cmake_ninja_dyndep does not understand the ", arg_modmapfmt,
@@ -2553,7 +2639,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
// Extend the module map with those provided by this target.
// We do this after loading the modules provided by linked targets
// in case we have one of the same name that must be preferred.
- Json::Value tm = Json::objectValue;
+ Json::Value target_modules = Json::objectValue;
for (cmScanDepInfo const& object : objects) {
for (auto const& p : object.Provides) {
std::string mod;
@@ -2572,7 +2658,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
mod = cmStrCat(module_dir, safe_logical_name, module_ext);
}
mod_files[p.LogicalName] = mod;
- tm[p.LogicalName] = mod;
+ target_modules[p.LogicalName] = mod;
}
}
@@ -2594,6 +2680,18 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
return {};
};
+ // Insert information about the current target's modules.
+ if (modmap_fmt) {
+ auto cycle_modules = CxxModuleUsageSeed(locs, objects, usages);
+ if (!cycle_modules.empty()) {
+ cmSystemTools::Error(
+ cmStrCat("Circular dependency detected in the C++ module import "
+ "graph. See modules named: \"",
+ cmJoin(cycle_modules, R"(", ")"_s), '"'));
+ return false;
+ }
+ }
+
cmNinjaBuild build("dyndep");
build.Outputs.emplace_back("");
for (cmScanDepInfo const& object : objects) {
@@ -2616,7 +2714,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
}
if (modmap_fmt) {
- auto mm = CxxModuleMapContent(*modmap_fmt, locs, object);
+ auto mm = CxxModuleMapContent(*modmap_fmt, locs, object, usages);
// XXX(modmap): If changing this path construction, change
// `cmNinjaTargetGenerator::WriteObjectBuildStatements` to generate the
@@ -2629,14 +2727,318 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
}
}
+ Json::Value target_module_info = Json::objectValue;
+ target_module_info["modules"] = target_modules;
+
+ auto& target_usages = target_module_info["usages"] = Json::objectValue;
+ for (auto const& u : usages.Usage) {
+ auto& mod_usage = target_usages[u.first] = Json::arrayValue;
+ for (auto const& v : u.second) {
+ mod_usage.append(v);
+ }
+ }
+
+ auto name_for_method = [](LookupMethod method) -> cm::static_string_view {
+ switch (method) {
+ case LookupMethod::ByName:
+ return "by-name"_s;
+ case LookupMethod::IncludeAngle:
+ return "include-angle"_s;
+ case LookupMethod::IncludeQuote:
+ return "include-quote"_s;
+ }
+ assert(false && "unsupported lookup method");
+ return ""_s;
+ };
+
+ auto& target_references = target_module_info["references"] =
+ Json::objectValue;
+ for (auto const& r : usages.Reference) {
+ auto& mod_ref = target_references[r.first] = Json::objectValue;
+ mod_ref["path"] = r.second.Path;
+ mod_ref["lookup-method"] = std::string(name_for_method(r.second.Method));
+ }
+
// Store the map of modules provided by this target in a file for
// use by dependents that reference this target in linked-target-dirs.
std::string const target_mods_file = cmStrCat(
cmSystemTools::GetFilenamePath(arg_dd), '/', arg_lang, "Modules.json");
cmGeneratedFileStream tmf(target_mods_file);
- tmf << tm;
+ tmf << target_module_info;
+
+ bool result = true;
+
+ // Fortran doesn't support any of the file-set or BMI installation considered
+ // below.
+ if (arg_lang != "Fortran"_s) {
+ // Prepare the export information blocks.
+ std::string const config_upper =
+ cmSystemTools::UpperCase(export_info.Config);
+ std::vector<std::pair<std::unique_ptr<cmGeneratedFileStream>,
+ CxxModuleExport const*>>
+ exports;
+ for (auto const& exp : export_info.Exports) {
+ std::unique_ptr<cmGeneratedFileStream> properties;
+
+ std::string const export_dir =
+ cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/');
+ std::string const property_file_path = cmStrCat(
+ export_dir, "target-", exp.Name, '-', export_info.Config, ".cmake");
+ properties = cm::make_unique<cmGeneratedFileStream>(property_file_path);
+
+ // Set up the preamble.
+ *properties << "set_property(TARGET \"" << exp.Namespace << exp.Name
+ << "\"\n"
+ << " PROPERTY IMPORTED_CXX_MODULES_" << config_upper
+ << '\n';
+
+ exports.emplace_back(std::move(properties), &exp);
+ }
+
+ std::unique_ptr<cmGeneratedFileStream> bmi_install_script;
+ if (export_info.BmiInstallation) {
+ bmi_install_script = cm::make_unique<cmGeneratedFileStream>(
+ export_info.BmiInstallation->ScriptLocation);
+ }
+
+ auto cmEscape = [](cm::string_view str) {
+ return cmOutputConverter::EscapeForCMake(
+ str, cmOutputConverter::WrapQuotes::NoWrap);
+ };
+ auto install_destination =
+ [&cmEscape](std::string const& dest) -> std::pair<bool, std::string> {
+ if (cmSystemTools::FileIsFullPath(dest)) {
+ return std::make_pair(true, cmEscape(dest));
+ }
+ return std::make_pair(false,
+ cmStrCat("${_IMPORT_PREFIX}/", cmEscape(dest)));
+ };
- return true;
+ // public/private requirement tracking.
+ std::set<std::string> private_modules;
+ std::map<std::string, std::set<std::string>> public_source_requires;
+
+ for (cmScanDepInfo const& object : objects) {
+ // Convert to forward slashes.
+ auto output_path = object.PrimaryOutput;
+# ifdef _WIN32
+ cmSystemTools::ConvertToUnixSlashes(output_path);
+# endif
+ // Find the fileset for this object.
+ auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path);
+ bool const has_provides = !object.Provides.empty();
+ if (fileset_info_itr == export_info.ObjectToFileSet.end()) {
+ // If it provides anything, it should have a `CXX_MODULES` or
+ // `CXX_MODULE_INTERNAL_PARTITIONS` type and be present.
+ if (has_provides) {
+ // Take the first module provided to provide context.
+ auto const& provides = object.Provides[0];
+ char const* ok_types = "`CXX_MODULES`";
+ if (provides.LogicalName.find(':') != std::string::npos) {
+ ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
+ "it is not `export`ed)";
+ }
+ cmSystemTools::Error(
+ cmStrCat("Output ", object.PrimaryOutput, " provides the `",
+ provides.LogicalName,
+ "` module but it is not found in a `FILE_SET` of type ",
+ ok_types));
+ result = false;
+ }
+
+ // This object file does not provide anything, so nothing more needs to
+ // be done.
+ continue;
+ }
+
+ auto const& file_set = fileset_info_itr->second;
+
+ // Verify the fileset type for the object.
+ if (file_set.Type == "CXX_MODULES"_s) {
+ if (!has_provides) {
+ cmSystemTools::Error(cmStrCat(
+ "Output ", object.PrimaryOutput,
+ " is of type `CXX_MODULES` but does not provide a module"));
+ result = false;
+ continue;
+ }
+ } else if (file_set.Type == "CXX_MODULE_INTERNAL_PARTITIONS"_s) {
+ if (!has_provides) {
+ cmSystemTools::Error(cmStrCat(
+ "Source ", file_set.SourcePath,
+ " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
+ "provide a module"));
+ result = false;
+ continue;
+ }
+ auto const& provides = object.Provides[0];
+ if (provides.LogicalName.find(':') == std::string::npos) {
+ cmSystemTools::Error(cmStrCat(
+ "Source ", file_set.SourcePath,
+ " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
+ "provide a module partition"));
+ result = false;
+ continue;
+ }
+ } else if (file_set.Type == "CXX_MODULE_HEADERS"_s) {
+ // TODO.
+ } else {
+ if (has_provides) {
+ auto const& provides = object.Provides[0];
+ char const* ok_types = "`CXX_MODULES`";
+ if (provides.LogicalName.find(':') != std::string::npos) {
+ ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
+ "it is not `export`ed)";
+ }
+ cmSystemTools::Error(cmStrCat(
+ "Source ", file_set.SourcePath, " provides the `",
+ provides.LogicalName, "` C++ module but is of type `",
+ file_set.Type, "` module but must be of type ", ok_types));
+ result = false;
+ }
+
+ // Not a C++ module; ignore.
+ continue;
+ }
+
+ if (!cmFileSetVisibilityIsForInterface(file_set.Visibility)) {
+ // Nothing needs to be conveyed about non-`PUBLIC` modules.
+ for (auto const& p : object.Provides) {
+ private_modules.insert(p.LogicalName);
+ }
+ continue;
+ }
+
+ // The module is public. Record what it directly requires.
+ {
+ auto& reqs = public_source_requires[file_set.SourcePath];
+ for (auto const& r : object.Requires) {
+ reqs.insert(r.LogicalName);
+ }
+ }
+
+ // Write out properties and install rules for any exports.
+ for (auto const& p : object.Provides) {
+ bool bmi_dest_is_abs = false;
+ std::string bmi_destination;
+ if (export_info.BmiInstallation) {
+ auto dest =
+ install_destination(export_info.BmiInstallation->Destination);
+ bmi_dest_is_abs = dest.first;
+ bmi_destination = cmStrCat(dest.second, '/');
+ }
+
+ std::string install_bmi_path;
+ std::string build_bmi_path;
+ auto m = mod_files.find(p.LogicalName);
+ if (m != mod_files.end()) {
+ install_bmi_path =
+ cmStrCat(bmi_destination,
+ cmEscape(cmSystemTools::GetFilenameName(m->second)));
+ build_bmi_path = cmEscape(m->second);
+ }
+
+ for (auto const& exp : exports) {
+ std::string iface_source;
+ if (exp.second->Install && file_set.Destination) {
+ auto dest = install_destination(*file_set.Destination);
+ iface_source = cmStrCat(
+ dest.second, '/', cmEscape(file_set.RelativeDirectory),
+ cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath)));
+ } else {
+ iface_source = cmEscape(file_set.SourcePath);
+ }
+
+ std::string bmi_path;
+ if (exp.second->Install && export_info.BmiInstallation) {
+ bmi_path = install_bmi_path;
+ } else if (!exp.second->Install) {
+ bmi_path = build_bmi_path;
+ }
+
+ if (iface_source.empty()) {
+ // No destination for the C++ module source; ignore this property
+ // value.
+ continue;
+ }
+
+ *exp.first << " \"" << cmEscape(p.LogicalName) << '='
+ << iface_source;
+ if (!bmi_path.empty()) {
+ *exp.first << ',' << bmi_path;
+ }
+ *exp.first << "\"\n";
+ }
+
+ if (bmi_install_script) {
+ auto const& bmi_install = *export_info.BmiInstallation;
+
+ *bmi_install_script << "if (CMAKE_INSTALL_COMPONENT STREQUAL \""
+ << cmEscape(bmi_install.Component) << '\"';
+ if (!bmi_install.ExcludeFromAll) {
+ *bmi_install_script << " OR NOT CMAKE_INSTALL_COMPONENT";
+ }
+ *bmi_install_script << ")\n";
+ *bmi_install_script << " file(INSTALL\n"
+ " DESTINATION \"";
+ if (!bmi_dest_is_abs) {
+ *bmi_install_script << "${CMAKE_INSTALL_PREFIX}/";
+ }
+ *bmi_install_script << cmEscape(bmi_install.Destination)
+ << "\"\n"
+ " TYPE FILE\n";
+ if (bmi_install.Optional) {
+ *bmi_install_script << " OPTIONAL\n";
+ }
+ if (!bmi_install.MessageLevel.empty()) {
+ *bmi_install_script << " " << bmi_install.MessageLevel << "\n";
+ }
+ if (!bmi_install.Permissions.empty()) {
+ *bmi_install_script << " PERMISSIONS" << bmi_install.Permissions
+ << "\n";
+ }
+ *bmi_install_script << " FILES \"" << m->second << "\")\n";
+ if (bmi_dest_is_abs) {
+ *bmi_install_script
+ << " list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"
+ " \""
+ << cmEscape(cmSystemTools::GetFilenameName(m->second))
+ << "\")\n"
+ " if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
+ " message(WARNING\n"
+ " \"ABSOLUTE path INSTALL DESTINATION : "
+ "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
+ " endif ()\n"
+ " if (CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
+ " message(FATAL_ERROR\n"
+ " \"ABSOLUTE path INSTALL DESTINATION forbidden (by "
+ "caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
+ " endif ()\n";
+ }
+ *bmi_install_script << "endif ()\n";
+ }
+ }
+ }
+
+ // Add trailing parenthesis for the `set_property` call.
+ for (auto const& exp : exports) {
+ *exp.first << ")\n";
+ }
+
+ // Check that public sources only require public modules.
+ for (auto const& pub_reqs : public_source_requires) {
+ for (auto const& req : pub_reqs.second) {
+ if (private_modules.count(req)) {
+ cmSystemTools::Error(cmStrCat(
+ "Public C++ module source `", pub_reqs.first, "` requires the `",
+ req, "` C++ module which is provided by a private source"));
+ result = false;
+ }
+ }
+ }
+ }
+
+ return result;
}
int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
@@ -2710,6 +3112,59 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
}
}
+ cmGlobalNinjaGenerator::CxxModuleExportInfo export_info;
+ export_info.Config = tdi["config"].asString();
+ if (export_info.Config.empty()) {
+ export_info.Config = "noconfig";
+ }
+ Json::Value const& tdi_exports = tdi["exports"];
+ if (tdi_exports.isArray()) {
+ for (auto const& tdi_export : tdi_exports) {
+ CxxModuleExport exp;
+ exp.Install = tdi_export["install"].asBool();
+ exp.Name = tdi_export["export-name"].asString();
+ exp.Destination = tdi_export["destination"].asString();
+ exp.Prefix = tdi_export["export-prefix"].asString();
+ exp.CxxModuleInfoDir = tdi_export["cxx-module-info-dir"].asString();
+ exp.Namespace = tdi_export["namespace"].asString();
+
+ export_info.Exports.push_back(exp);
+ }
+ }
+ auto const& bmi_installation = tdi["bmi-installation"];
+ if (bmi_installation.isObject()) {
+ CxxModuleBmiInstall bmi_install;
+
+ bmi_install.Component = bmi_installation["component"].asString();
+ bmi_install.Destination = bmi_installation["destination"].asString();
+ bmi_install.ExcludeFromAll = bmi_installation["exclude-from-all"].asBool();
+ bmi_install.Optional = bmi_installation["optional"].asBool();
+ bmi_install.Permissions = bmi_installation["permissions"].asString();
+ bmi_install.MessageLevel = bmi_installation["message-level"].asString();
+ bmi_install.ScriptLocation =
+ bmi_installation["script-location"].asString();
+
+ export_info.BmiInstallation = bmi_install;
+ }
+ Json::Value const& tdi_cxx_modules = tdi["cxx-modules"];
+ if (tdi_cxx_modules.isObject()) {
+ for (auto i = tdi_cxx_modules.begin(); i != tdi_cxx_modules.end(); ++i) {
+ CxxModuleFileSet& fsi = export_info.ObjectToFileSet[i.key().asString()];
+ auto const& tdi_cxx_module_info = *i;
+ fsi.Name = tdi_cxx_module_info["name"].asString();
+ fsi.RelativeDirectory =
+ tdi_cxx_module_info["relative-directory"].asString();
+ fsi.SourcePath = tdi_cxx_module_info["source"].asString();
+ fsi.Type = tdi_cxx_module_info["type"].asString();
+ fsi.Visibility = cmFileSetVisibilityFromName(
+ tdi_cxx_module_info["visibility"].asString(), nullptr);
+ auto const& tdi_fs_dest = tdi_cxx_module_info["destination"];
+ if (tdi_fs_dest.isString()) {
+ fsi.Destination = tdi_fs_dest.asString();
+ }
+ }
+ }
+
cmake cm(cmake::RoleInternal, cmState::Unknown);
cm.SetHomeDirectory(dir_top_src);
cm.SetHomeOutputDirectory(dir_top_bld);
@@ -2717,7 +3172,8 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
if (!ggd ||
!cm::static_reference_cast<cmGlobalNinjaGenerator>(ggd).WriteDyndepFile(
dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld, arg_dd, arg_ddis,
- module_dir, linked_target_dirs, arg_lang, arg_modmapfmt)) {
+ module_dir, linked_target_dirs, arg_lang, arg_modmapfmt,
+ export_info)) {
return 1;
}
return 0;
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index aa2df4d..dc4f444 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -417,13 +417,15 @@ public:
bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
void StripNinjaOutputPathPrefixAsSuffix(std::string& path);
+ struct CxxModuleExportInfo;
bool WriteDyndepFile(
std::string const& dir_top_src, std::string const& dir_top_bld,
std::string const& dir_cur_src, std::string const& dir_cur_bld,
std::string const& arg_dd, std::vector<std::string> const& arg_ddis,
std::string const& module_dir,
std::vector<std::string> const& linked_target_dirs,
- std::string const& arg_lang, std::string const& arg_modmapfmt);
+ std::string const& arg_lang, std::string const& arg_modmapfmt,
+ CxxModuleExportInfo const& export_info);
virtual std::string BuildAlias(const std::string& alias,
const std::string& /*config*/) const
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index ab9ca50..21aa89c 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -181,12 +181,12 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
return;
}
- // get a local generator for some useful methods
- auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
+ // The global dependency graph is expressed via the root local generator.
+ auto& rootLG = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
this->LocalGenerators[0]);
// Write the do not edit header.
- lg.WriteDisclaimer(makefileStream);
+ rootLG.WriteDisclaimer(makefileStream);
// Write the main entry point target. This must be the VERY first
// target so that make with no arguments will run it.
@@ -196,10 +196,10 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
depends.emplace_back("all");
// Write the rule.
- lg.WriteMakeRule(makefileStream,
- "Default target executed when no arguments are "
- "given to make.",
- "default_target", depends, no_commands, true);
+ rootLG.WriteMakeRule(makefileStream,
+ "Default target executed when no arguments are "
+ "given to make.",
+ "default_target", depends, no_commands, true);
depends.clear();
@@ -210,22 +210,22 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
}
// Write out the "special" stuff
- lg.WriteSpecialTargetsTop(makefileStream);
+ rootLG.WriteSpecialTargetsTop(makefileStream);
// Write the directory level rules.
for (auto const& it : this->ComputeDirectoryTargets()) {
- this->WriteDirectoryRules2(makefileStream, it.second);
+ this->WriteDirectoryRules2(makefileStream, rootLG, it.second);
}
// Write the target convenience rules
for (const auto& localGen : this->LocalGenerators) {
this->WriteConvenienceRules2(
- makefileStream,
+ makefileStream, rootLG,
cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen));
}
// Write special bottom targets
- lg.WriteSpecialTargetsBottom(makefileStream);
+ rootLG.WriteSpecialTargetsBottom(makefileStream);
}
void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
@@ -359,8 +359,9 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefileLanguageRules(
}
void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
- std::ostream& ruleFileStream, DirectoryTarget const& dt, const char* pass,
- bool check_all, bool check_relink, std::vector<std::string> const& commands)
+ std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3& rootLG,
+ DirectoryTarget const& dt, const char* pass, bool check_all,
+ bool check_relink, std::vector<std::string> const& commands)
{
auto* lg = static_cast<cmLocalUnixMakefileGenerator3*>(dt.LG);
std::string makeTarget =
@@ -406,19 +407,21 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
} else {
doc = cmStrCat("Recursive \"", pass, "\" directory target.");
}
- lg->WriteMakeRule(ruleFileStream, doc.c_str(), makeTarget, depends, commands,
- true);
+
+ rootLG.WriteMakeRule(ruleFileStream, doc.c_str(), makeTarget, depends,
+ commands, true);
}
void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2(
- std::ostream& ruleFileStream, DirectoryTarget const& dt)
+ std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3& rootLG,
+ DirectoryTarget const& dt)
{
auto* lg = static_cast<cmLocalUnixMakefileGenerator3*>(dt.LG);
// Begin the directory-level rules section.
{
std::string dir = cmSystemTools::ConvertToOutputPath(
- lg->MaybeRelativeToTopBinDir(lg->GetCurrentBinaryDirectory()));
- lg->WriteDivider(ruleFileStream);
+ rootLG.MaybeRelativeToTopBinDir(lg->GetCurrentBinaryDirectory()));
+ rootLG.WriteDivider(ruleFileStream);
if (lg->IsRootMakefile()) {
ruleFileStream << "# Directory level rules for the build root directory";
} else {
@@ -428,16 +431,18 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2(
}
// Write directory-level rules for "all".
- this->WriteDirectoryRule2(ruleFileStream, dt, "all", true, false);
+ this->WriteDirectoryRule2(ruleFileStream, rootLG, dt, "all", true, false);
// Write directory-level rules for "preinstall".
- this->WriteDirectoryRule2(ruleFileStream, dt, "preinstall", true, true);
+ this->WriteDirectoryRule2(ruleFileStream, rootLG, dt, "preinstall", true,
+ true);
// Write directory-level rules for "clean".
{
std::vector<std::string> cmds;
lg->AppendDirectoryCleanCommand(cmds);
- this->WriteDirectoryRule2(ruleFileStream, dt, "clean", false, false, cmds);
+ this->WriteDirectoryRule2(ruleFileStream, rootLG, dt, "clean", false,
+ false, cmds);
}
}
@@ -632,7 +637,8 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules(
}
void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
- std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3& lg)
+ std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3& rootLG,
+ cmLocalUnixMakefileGenerator3& lg)
{
std::vector<std::string> depends;
std::vector<std::string> commands;
@@ -696,8 +702,8 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
}
this->AppendGlobalTargetDepends(depends, gtarget.get());
- lg.WriteMakeRule(ruleFileStream, "All Build rule for target.", localName,
- depends, commands, true);
+ rootLG.WriteMakeRule(ruleFileStream, "All Build rule for target.",
+ localName, depends, commands, true);
// Write the rule.
commands.clear();
@@ -731,16 +737,16 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
}
localName =
cmStrCat(lg.GetRelativeTargetDirectory(gtarget.get()), "/rule");
- lg.WriteMakeRule(ruleFileStream,
- "Build rule for subdir invocation for target.",
- localName, depends, commands, true);
+ rootLG.WriteMakeRule(ruleFileStream,
+ "Build rule for subdir invocation for target.",
+ localName, depends, commands, true);
// Add a target with the canonical name (no prefix, suffix or path).
commands.clear();
depends.clear();
depends.push_back(localName);
- lg.WriteMakeRule(ruleFileStream, "Convenience name for target.", name,
- depends, commands, true);
+ rootLG.WriteMakeRule(ruleFileStream, "Convenience name for target.",
+ name, depends, commands, true);
// Add rules to prepare the target for installation.
if (gtarget->NeedRelinkBeforeInstall(lg.GetConfigName())) {
@@ -749,8 +755,9 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
depends.clear();
commands.clear();
commands.push_back(lg.GetRecursiveMakeCall(makefileName, localName));
- lg.WriteMakeRule(ruleFileStream, "Pre-install relink rule for target.",
- localName, depends, commands, true);
+ rootLG.WriteMakeRule(ruleFileStream,
+ "Pre-install relink rule for target.", localName,
+ depends, commands, true);
}
// add the clean rule
@@ -760,8 +767,8 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
commands.clear();
commands.push_back(
lg.GetRecursiveMakeCall(makefileName, makeTargetName));
- lg.WriteMakeRule(ruleFileStream, "clean rule for target.",
- makeTargetName, depends, commands, true);
+ rootLG.WriteMakeRule(ruleFileStream, "clean rule for target.",
+ makeTargetName, depends, commands, true);
commands.clear();
}
}
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index 5157826..b9d333e 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -200,13 +200,16 @@ protected:
void WriteMainCMakefile();
void WriteConvenienceRules2(std::ostream& ruleFileStream,
- cmLocalUnixMakefileGenerator3&);
+ cmLocalUnixMakefileGenerator3& rootLG,
+ cmLocalUnixMakefileGenerator3& lg);
void WriteDirectoryRule2(std::ostream& ruleFileStream,
+ cmLocalUnixMakefileGenerator3& rootLG,
DirectoryTarget const& dt, const char* pass,
bool check_all, bool check_relink,
std::vector<std::string> const& commands = {});
void WriteDirectoryRules2(std::ostream& ruleFileStream,
+ cmLocalUnixMakefileGenerator3& rootLG,
DirectoryTarget const& dt);
void AppendGlobalTargetDepends(std::vector<std::string>& depends,
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index 155efde..7886fc7 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -389,6 +389,27 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
this->GeneratorToolsetVersion.clear();
this->GeneratorToolsetVersionProps = {};
} break;
+ case AuxToolset::PropsIndeterminate: {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "given toolset and version specification\n"
+ " " << this->GetPlatformToolsetString() << ",version=" <<
+ this->GeneratorToolsetVersion << "\n"
+ "has multiple matches installed at\n" <<
+ " " << auxProps << "\n" <<
+ "The toolset and version specification must resolve \n" <<
+ "to a single installed toolset";
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+
+ // Clear the configured tool-set
+ this->GeneratorToolsetVersion.clear();
+ this->GeneratorToolsetVersionProps = {};
+ } break;
}
}
@@ -1286,14 +1307,6 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand(
return makeCommands;
}
-bool cmGlobalVisualStudio10Generator::IsInSolution(
- const cmGeneratorTarget* gt) const
-{
- return gt->IsInBuildSystem() &&
- !(this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS16 &&
- gt->GetName() == CMAKE_CHECK_BUILD_SYSTEM_TARGET);
-}
-
bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
{
if (this->DefaultPlatformToolset == "v100") {
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index 2203f71..a33c94e 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -118,8 +118,6 @@ public:
return this->WindowsTargetPlatformVersion;
}
- bool IsInSolution(const cmGeneratorTarget* gt) const override;
-
/** Return true if building for WindowsCE */
bool TargetsWindowsCE() const override { return this->SystemIsWindowsCE; }
@@ -202,7 +200,8 @@ protected:
None,
Default,
PropsExist,
- PropsMissing
+ PropsMissing,
+ PropsIndeterminate
};
virtual AuxToolset FindAuxToolset(std::string& version,
std::string& props) const;
diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx
index ce943a2..758ce83 100644
--- a/Source/cmGlobalVisualStudio71Generator.cxx
+++ b/Source/cmGlobalVisualStudio71Generator.cxx
@@ -180,7 +180,7 @@ void cmGlobalVisualStudio71Generator::WriteExternalProject(
fout << "\tProjectSection(ProjectDependencies) = postProject\n";
for (BT<std::pair<std::string, bool>> const& it : depends) {
std::string const& dep = it.Value.first;
- if (!dep.empty()) {
+ if (this->IsDepInSolution(dep)) {
fout << "\t\t{" << this->GetGUID(dep) << "} = {" << this->GetGUID(dep)
<< "}\n";
}
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index cddaaa4..c6af20a 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -843,6 +843,12 @@ bool cmGlobalVisualStudioGenerator::IsInSolution(
return gt->IsInBuildSystem();
}
+bool cmGlobalVisualStudioGenerator::IsDepInSolution(
+ const std::string& targetName) const
+{
+ return !targetName.empty();
+}
+
bool cmGlobalVisualStudioGenerator::TargetCompare::operator()(
cmGeneratorTarget const* l, cmGeneratorTarget const* r) const
{
diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h
index 4f5f100..f45b4d4 100644
--- a/Source/cmGlobalVisualStudioGenerator.h
+++ b/Source/cmGlobalVisualStudioGenerator.h
@@ -101,6 +101,9 @@ public:
// return true if target should be included in solution.
virtual bool IsInSolution(const cmGeneratorTarget* gt) const;
+ // return true if project dependency should be included in solution.
+ virtual bool IsDepInSolution(const std::string& targetName) const;
+
/** Get the top-level registry key for this VS version. */
std::string GetRegistryBase();
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
index b72fc4e..c3ba2c2 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
@@ -25,53 +25,100 @@
#include "cmVSSetupHelper.h"
#include "cmake.h"
-#if defined(_M_ARM64)
-# define HOST_PLATFORM_NAME "ARM64"
-# define HOST_TOOLS_ARCH(v) \
- (v >= cmGlobalVisualStudioGenerator::VSVersion::VS17) ? "ARM64" : ""
-#elif defined(_M_ARM)
-# define HOST_PLATFORM_NAME "ARM"
-# define HOST_TOOLS_ARCH(v) ""
-#elif defined(_M_IA64)
-# define HOST_PLATFORM_NAME "Itanium"
-# define HOST_TOOLS_ARCH(v) ""
-#elif defined(_WIN64)
-# define HOST_PLATFORM_NAME "x64"
-# define HOST_TOOLS_ARCH(v) "x64"
-#else
+#ifndef IMAGE_FILE_MACHINE_ARM64
+# define IMAGE_FILE_MACHINE_ARM64 0xaa64 // ARM64 Little-Endian
+#endif
+
static bool VSIsWow64()
{
BOOL isWow64 = false;
return IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64;
}
+
+static bool VSIsArm64Host()
+{
+ typedef BOOL(WINAPI * CM_ISWOW64PROCESS2)(
+ HANDLE hProcess, USHORT * pProcessMachine, USHORT * pNativeMachine);
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+# define CM_VS_GCC_DIAGNOSTIC_PUSHED
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+ static const CM_ISWOW64PROCESS2 s_IsWow64Process2Impl =
+ (CM_ISWOW64PROCESS2)GetProcAddress(
+ GetModuleHandleW(L"api-ms-win-core-wow64-l1-1-1.dll"),
+ "IsWow64Process2");
+#ifdef CM_VS_GCC_DIAGNOSTIC_PUSHED
+# pragma GCC diagnostic pop
+# undef CM_VS_GCC_DIAGNOSTIC_PUSHED
#endif
+ USHORT processMachine, nativeMachine;
+
+ return s_IsWow64Process2Impl != nullptr &&
+ s_IsWow64Process2Impl(GetCurrentProcess(), &processMachine,
+ &nativeMachine) &&
+ nativeMachine == IMAGE_FILE_MACHINE_ARM64;
+}
+
+static bool VSHasDotNETFrameworkArm64()
+{
+ std::string dotNetArm64;
+ return cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\.NETFramework;InstallRootArm64",
+ dotNetArm64, cmSystemTools::KeyWOW64_64);
+}
+
+static bool VSIsWindows11OrGreater()
+{
+ cmSystemTools::WindowsVersion const windowsVersion =
+ cmSystemTools::GetWindowsVersion();
+ return (windowsVersion.dwMajorVersion > 10 ||
+ (windowsVersion.dwMajorVersion == 10 &&
+ windowsVersion.dwMinorVersion > 0) ||
+ (windowsVersion.dwMajorVersion == 10 &&
+ windowsVersion.dwMinorVersion == 0 &&
+ windowsVersion.dwBuildNumber >= 22000));
+}
+
static std::string VSHostPlatformName()
{
-#ifdef HOST_PLATFORM_NAME
- return HOST_PLATFORM_NAME;
-#else
- if (VSIsWow64()) {
+ if (VSIsArm64Host()) {
+ return "ARM64";
+ } else if (VSIsWow64()) {
return "x64";
} else {
+#if defined(_M_ARM)
+ return "ARM";
+#elif defined(_M_IA64)
+ return "Itanium";
+#elif defined(_WIN64)
+ return "x64";
+#else
return "Win32";
- }
#endif
+ }
}
static std::string VSHostArchitecture(
cmGlobalVisualStudioGenerator::VSVersion v)
{
- static_cast<void>(v);
-#ifdef HOST_TOOLS_ARCH
- return HOST_TOOLS_ARCH(v);
-#else
- if (VSIsWow64()) {
+ if (VSIsArm64Host()) {
+ return v >= cmGlobalVisualStudioGenerator::VSVersion::VS17 ? "ARM64" : "";
+ } else if (VSIsWow64()) {
return "x64";
} else {
+#if defined(_M_ARM)
+ return "";
+#elif defined(_M_IA64)
+ return "";
+#elif defined(_WIN64)
+ return "x64";
+#else
return "x86";
- }
#endif
+ }
}
static unsigned int VSVersionToMajor(
@@ -723,12 +770,15 @@ cmGlobalVisualStudioVersionedGenerator::FindAuxToolset(
cmSystemTools::ConvertToUnixSlashes(instancePath);
// Translate three-component format accepted by "vcvarsall -vcvars_ver=".
- cmsys::RegularExpression threeComponent(
+ cmsys::RegularExpression threeComponentRegex(
"^([0-9]+\\.[0-9]+)\\.[0-9][0-9][0-9][0-9][0-9]$");
- if (threeComponent.find(version)) {
+ // The two-component format represents the two major components of the
+ // three-component format
+ cmsys::RegularExpression twoComponentRegex("^([0-9]+\\.[0-9]+)$");
+ if (threeComponentRegex.find(version)) {
// Load "VC/Auxiliary/Build/*/Microsoft.VCToolsVersion.*.txt" files
// with two matching components to check their three-component version.
- std::string const& twoComponent = threeComponent.match(1);
+ std::string const& twoComponent = threeComponentRegex.match(1);
std::string pattern =
cmStrCat(instancePath, "/VC/Auxiliary/Build/"_s, twoComponent,
"*/Microsoft.VCToolsVersion."_s, twoComponent, "*.txt"_s);
@@ -754,6 +804,34 @@ cmGlobalVisualStudioVersionedGenerator::FindAuxToolset(
}
}
}
+ } else if (twoComponentRegex.find(version)) {
+ std::string const& twoComponent = twoComponentRegex.match(1);
+ std::string pattern =
+ cmStrCat(instancePath, "/VC/Auxiliary/Build/"_s, twoComponent,
+ "*/Microsoft.VCToolsVersion."_s, twoComponent, "*.txt"_s);
+ cmsys::Glob glob;
+ glob.SetRecurseThroughSymlinks(false);
+ // Since we are only using the first two components of the toolset version,
+ // we require a definite match
+ if (glob.FindFiles(pattern) && glob.GetFiles().size() == 1) {
+ std::string const& txt = glob.GetFiles()[0];
+ std::string ver;
+ cmsys::ifstream fin(txt.c_str());
+ if (fin && std::getline(fin, ver)) {
+ // Strip trailing whitespace.
+ ver = ver.substr(0, ver.find_first_not_of("0123456789."));
+ // We assume the version is correct, since it is the only one that
+ // matched.
+ cmsys::RegularExpression extractVersion(
+ "VCToolsVersion\\.([0-9.]+)\\.txt$");
+ if (extractVersion.find(txt)) {
+ version = extractVersion.match(1);
+ }
+ }
+ } else {
+ props = cmStrCat(instancePath, "/VC/Auxiliary/Build/"_s);
+ return AuxToolset::PropsIndeterminate;
+ }
}
if (cmSystemTools::VersionCompareGreaterEq(version, "14.20")) {
@@ -899,17 +977,24 @@ std::string cmGlobalVisualStudioVersionedGenerator::FindMSBuildCommand()
std::string vs;
if (vsSetupAPIHelper.GetVSInstanceInfo(vs)) {
if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS17) {
-#if defined(_M_ARM64)
- std::string msbuild_arm64 =
- vs + "/MSBuild/Current/Bin/arm64/MSBuild.exe";
- if (cmSystemTools::FileExists(msbuild_arm64)) {
- return msbuild_arm64;
- }
-#endif
-
- msbuild = vs + "/MSBuild/Current/Bin/amd64/MSBuild.exe";
- if (cmSystemTools::FileExists(msbuild)) {
- return msbuild;
+ if (VSIsArm64Host()) {
+ if (VSHasDotNETFrameworkArm64()) {
+ msbuild = vs + "/MSBuild/Current/Bin/arm64/MSBuild.exe";
+ if (cmSystemTools::FileExists(msbuild)) {
+ return msbuild;
+ }
+ }
+ if (VSIsWindows11OrGreater()) {
+ msbuild = vs + "/MSBuild/Current/Bin/amd64/MSBuild.exe";
+ if (cmSystemTools::FileExists(msbuild)) {
+ return msbuild;
+ }
+ }
+ } else {
+ msbuild = vs + "/MSBuild/Current/Bin/amd64/MSBuild.exe";
+ if (cmSystemTools::FileExists(msbuild)) {
+ return msbuild;
+ }
}
}
msbuild = vs + "/MSBuild/Current/Bin/MSBuild.exe";
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 5738799..9739a4e 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -1192,13 +1192,9 @@ std::string GetTargetObjectDirArch(T const& target,
std::string cmGlobalXCodeGenerator::GetLibraryOrFrameworkPath(
const std::string& path) const
{
- auto fwItems = this->SplitFrameworkPath(path);
- if (fwItems) {
- if (fwItems->first.empty()) {
- return cmStrCat(fwItems->second, ".framework");
- } else {
- return cmStrCat(fwItems->first, '/', fwItems->second, ".framework");
- }
+ auto fwDescriptor = this->SplitFrameworkPath(path);
+ if (fwDescriptor) {
+ return fwDescriptor->GetFrameworkPath();
}
return path;
@@ -2368,8 +2364,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
std::string& flags = cflags[lang];
// Add language-specific flags.
- this->CurrentLocalGenerator->AddLanguageFlags(flags, gtgt, lang,
- configName);
+ this->CurrentLocalGenerator->AddLanguageFlags(
+ flags, gtgt, cmBuildStep::Compile, lang, configName);
if (gtgt->IsIPOEnabled(lang, configName)) {
this->CurrentLocalGenerator->AppendFeatureOptions(flags, lang, "IPO");
@@ -2423,6 +2419,18 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
this->AppendDefines(ppDefs, targetDefines);
buildSettings->AddAttribute("GCC_PREPROCESSOR_DEFINITIONS",
ppDefs.CreateList());
+ if (languages.count("Swift")) {
+ if (this->XcodeVersion < 80) {
+ std::string defineString;
+ std::set<std::string> defines(targetDefines.begin(),
+ targetDefines.end());
+ this->CurrentLocalGenerator->JoinDefines(defines, defineString, "Swift");
+ cflags["Swift"] += " " + defineString;
+ } else {
+ buildSettings->AddAttribute("SWIFT_ACTIVE_COMPILATION_CONDITIONS",
+ ppDefs.CreateList());
+ }
+ }
std::string extraLinkOptionsVar;
std::string extraLinkOptions;
@@ -2882,8 +2890,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
}
// Create the INSTALL_PATH attribute.
- std::string install_name_dir;
if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ std::string install_name_dir;
// Get the install_name directory for the build tree.
install_name_dir = gtgt->GetInstallNameDirForBuildTree(configName);
// Xcode doesn't create the correct install_name in some cases.
@@ -2905,9 +2913,9 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
extraLinkOptions += " -install_name ";
extraLinkOptions += XCodeEscapePath(install_name);
}
+ buildSettings->AddAttribute("INSTALL_PATH",
+ this->CreateString(install_name_dir));
}
- buildSettings->AddAttribute("INSTALL_PATH",
- this->CreateString(install_name_dir));
// Create the LD_RUNPATH_SEARCH_PATHS
cmComputeLinkInformation* pcli = gtgt->GetLinkInformation(configName);
@@ -3629,15 +3637,17 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
linkDir = libItem->Value.Value;
}
if (cmHasSuffix(libItem->GetFeatureName(), "FRAMEWORK"_s)) {
- auto fwItems = this->SplitFrameworkPath(linkDir, true);
- if (fwItems && !fwItems->first.empty()) {
- linkDir = std::move(fwItems->first);
+ auto fwDescriptor = this->SplitFrameworkPath(
+ linkDir, cmGlobalGenerator::FrameworkFormat::Extended);
+ if (fwDescriptor && !fwDescriptor->Directory.empty()) {
+ linkDir = fwDescriptor->Directory;
if (std::find(frameworkSearchPaths.begin(), frameworkSearchPaths.end(),
linkDir) == frameworkSearchPaths.end()) {
frameworkSearchPaths.push_back(linkDir);
}
}
} else {
+ linkDir = cmSystemTools::GetParentDirectory(linkDir);
if (std::find(linkSearchPaths.begin(), linkSearchPaths.end(), linkDir) ==
linkSearchPaths.end()) {
linkSearchPaths.push_back(linkDir);
@@ -3763,14 +3773,20 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
// add the library search paths
{
BuildObjectListOrString libSearchPaths(this, true);
+
std::string linkDirs;
for (auto const& libDir : cli->GetDirectories()) {
if (!libDir.empty() && libDir != "/usr/lib") {
- libSearchPaths.Add(this->XCodeEscapePath(
- libDir + "/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"));
+ cmPolicies::PolicyStatus cmp0142 =
+ target->GetTarget()->GetPolicyStatusCMP0142();
+ if (cmp0142 == cmPolicies::OLD || cmp0142 == cmPolicies::WARN) {
+ libSearchPaths.Add(this->XCodeEscapePath(
+ libDir + "/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"));
+ }
libSearchPaths.Add(this->XCodeEscapePath(libDir));
}
}
+
// Add previously collected paths where to look for libraries
// that were added to "Link Binary With Libraries"
for (auto& libDir : linkSearchPaths) {
@@ -3820,17 +3836,26 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
bool isFramework =
cmHasSuffix(libName.GetFeatureName(), "FRAMEWORK"_s);
if (isFramework) {
- const auto fwItems =
- this->SplitFrameworkPath(cleanPath, isFramework);
- if (!fwItems->first.empty() &&
- emitted.insert(fwItems->first).second) {
+ const auto fwDescriptor = this->SplitFrameworkPath(
+ cleanPath, cmGlobalGenerator::FrameworkFormat::Extended);
+ if (!fwDescriptor->Directory.empty() &&
+ emitted.insert(fwDescriptor->Directory).second) {
// This is a search path we had not added before and it isn't
// an implicit search path, so we need it
- libPaths.Add("-F " + this->XCodeEscapePath(fwItems->first));
+ libPaths.Add("-F " +
+ this->XCodeEscapePath(fwDescriptor->Directory));
+ }
+ if (libName.GetFeatureName() == "__CMAKE_LINK_FRAMEWORK"_s) {
+ // use the full path
+ libPaths.Add(
+ libName.GetFormattedItem(this->XCodeEscapePath(cleanPath))
+ .Value);
+ } else {
+ libPaths.Add(libName
+ .GetFormattedItem(this->XCodeEscapePath(
+ fwDescriptor->GetLinkName()))
+ .Value);
}
- libPaths.Add(
- libName.GetFormattedItem(this->XCodeEscapePath(fwItems->second))
- .Value);
} else {
libPaths.Add(
libName.GetFormattedItem(this->XCodeEscapePath(cleanPath))
diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx
index 0da72b1..c2a09c1 100644
--- a/Source/cmIfCommand.cxx
+++ b/Source/cmIfCommand.cxx
@@ -150,7 +150,7 @@ bool cmIfFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
cmExecutionStatus status(mf);
mf.ExecuteCommand(func, status);
if (status.GetReturnInvoked()) {
- inStatus.SetReturnInvoked();
+ inStatus.SetReturnInvoked(status.GetReturnVariables());
return true;
}
if (status.GetBreakInvoked()) {
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 7ca5b23..82adca8 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -12,18 +12,22 @@
#include <utility>
#include <cm/memory>
+#include <cm/optional>
#include <cm/string_view>
#include <cmext/string_view>
#include "cmsys/Glob.hxx"
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmExecutionStatus.h"
+#include "cmExperimental.h"
#include "cmExportSet.h"
#include "cmFileSet.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
#include "cmInstallCommandArguments.h"
+#include "cmInstallCxxModuleBmiGenerator.h"
#include "cmInstallDirectoryGenerator.h"
#include "cmInstallExportGenerator.h"
#include "cmInstallFileSetGenerator.h"
@@ -54,13 +58,13 @@ namespace {
struct RuntimeDependenciesArgs
{
- std::vector<std::string> Directories;
- std::vector<std::string> PreIncludeRegexes;
- std::vector<std::string> PreExcludeRegexes;
- std::vector<std::string> PostIncludeRegexes;
- std::vector<std::string> PostExcludeRegexes;
- std::vector<std::string> PostIncludeFiles;
- std::vector<std::string> PostExcludeFiles;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Directories;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PreIncludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PreExcludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeRegexes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeFiles;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeFiles;
};
auto const RuntimeDependenciesArgHelper =
@@ -109,6 +113,8 @@ public:
const cmInstallCommandArguments* args) const;
std::string GetLibraryDestination(
const cmInstallCommandArguments* args) const;
+ std::string GetCxxModulesBmiDestination(
+ const cmInstallCommandArguments* args) const;
std::string GetIncludeDestination(
const cmInstallCommandArguments* args) const;
std::string GetSysconfDestination(
@@ -401,16 +407,17 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
struct ArgVectors
{
- std::vector<std::string> Archive;
- std::vector<std::string> Library;
- std::vector<std::string> Runtime;
- std::vector<std::string> Object;
- std::vector<std::string> Framework;
- std::vector<std::string> Bundle;
- std::vector<std::string> Includes;
- std::vector<std::string> PrivateHeader;
- std::vector<std::string> PublicHeader;
- std::vector<std::string> Resource;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Archive;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Library;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Object;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Bundle;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Includes;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PrivateHeader;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> PublicHeader;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Resource;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> CxxModulesBmi;
std::vector<std::vector<std::string>> FileSets;
};
@@ -426,7 +433,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
.Bind("PRIVATE_HEADER"_s, &ArgVectors::PrivateHeader)
.Bind("PUBLIC_HEADER"_s, &ArgVectors::PublicHeader)
.Bind("RESOURCE"_s, &ArgVectors::Resource)
- .Bind("FILE_SET"_s, &ArgVectors::FileSets);
+ .Bind("FILE_SET"_s, &ArgVectors::FileSets)
+ .Bind("CXX_MODULES_BMI"_s, &ArgVectors::CxxModulesBmi);
std::vector<std::string> genericArgVector;
ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector);
@@ -434,26 +442,25 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
// now parse the generic args (i.e. the ones not specialized on LIBRARY/
// ARCHIVE, RUNTIME etc. (see above)
// These generic args also contain the targets and the export stuff
- std::vector<std::string> targetList;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> targetList;
std::string exports;
- std::vector<std::string> runtimeDependenciesArgVector;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>>
+ runtimeDependenciesArgVector;
std::string runtimeDependencySetArg;
std::vector<std::string> unknownArgs;
- std::vector<std::string> parsedArgs;
cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
genericArgs.Bind("TARGETS"_s, targetList);
genericArgs.Bind("EXPORT"_s, exports);
genericArgs.Bind("RUNTIME_DEPENDENCIES"_s, runtimeDependenciesArgVector);
genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
- genericArgs.Parse(genericArgVector, &unknownArgs, nullptr, &parsedArgs);
+ genericArgs.Parse(genericArgVector, &unknownArgs);
bool success = genericArgs.Finalize();
- bool withRuntimeDependencies =
- std::find(parsedArgs.begin(), parsedArgs.end(), "RUNTIME_DEPENDENCIES") !=
- parsedArgs.end();
RuntimeDependenciesArgs runtimeDependenciesArgs =
- RuntimeDependenciesArgHelper.Parse(runtimeDependenciesArgVector,
- &unknownArgs);
+ runtimeDependenciesArgVector
+ ? RuntimeDependenciesArgHelper.Parse(*runtimeDependenciesArgVector,
+ &unknownArgs)
+ : RuntimeDependenciesArgs();
cmInstallCommandArguments archiveArgs(helper.DefaultComponentName);
cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
@@ -467,6 +474,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
cmInstallCommandIncludesArgument includesArgs;
std::vector<cmInstallCommandFileSetArguments> fileSetArgs(
argVectors.FileSets.size(), { helper.DefaultComponentName });
+ cmInstallCommandArguments cxxModuleBmiArgs(helper.DefaultComponentName);
// now parse the args for specific parts of the target (e.g. LIBRARY,
// RUNTIME, ARCHIVE etc.
@@ -490,6 +498,15 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
fileSetArgs[i] = std::move(fileSetArg);
}
+ bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled(
+ *helper.Makefile, cmExperimental::Feature::CxxModuleCMakeApi);
+ if (!supportCxx20FileSetTypes) {
+ std::copy(argVectors.CxxModulesBmi.begin(), argVectors.CxxModulesBmi.end(),
+ std::back_inserter(unknownArgs));
+ } else {
+ cxxModuleBmiArgs.Parse(argVectors.CxxModulesBmi, &unknownArgs);
+ }
+
if (!unknownArgs.empty()) {
// Unknown argument.
status.SetError(
@@ -510,6 +527,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
for (auto& fileSetArg : fileSetArgs) {
fileSetArg.SetGenericArguments(&genericArgs);
}
+ cxxModuleBmiArgs.SetGenericArguments(&genericArgs);
success = success && archiveArgs.Finalize();
success = success && libraryArgs.Finalize();
@@ -523,6 +541,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
for (auto& fileSetArg : fileSetArgs) {
success = success && fileSetArg.Finalize();
}
+ if (supportCxx20FileSetTypes) {
+ success = success && cxxModuleBmiArgs.Finalize();
+ }
if (!success) {
return false;
@@ -536,7 +557,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
publicHeaderArgs.GetNamelinkOnly() || resourceArgs.GetNamelinkOnly() ||
std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
[](const cmInstallCommandFileSetArguments& fileSetArg)
- -> bool { return fileSetArg.GetNamelinkOnly(); })) {
+ -> bool { return fileSetArg.GetNamelinkOnly(); }) ||
+ cxxModuleBmiArgs.GetNamelinkOnly()) {
status.SetError(
"TARGETS given NAMELINK_ONLY option not in LIBRARY group. "
"The NAMELINK_ONLY option may be specified only following LIBRARY.");
@@ -548,7 +570,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
publicHeaderArgs.GetNamelinkSkip() || resourceArgs.GetNamelinkSkip() ||
std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
[](const cmInstallCommandFileSetArguments& fileSetArg)
- -> bool { return fileSetArg.GetNamelinkSkip(); })) {
+ -> bool { return fileSetArg.GetNamelinkSkip(); }) ||
+ cxxModuleBmiArgs.GetNamelinkSkip()) {
status.SetError(
"TARGETS given NAMELINK_SKIP option not in LIBRARY group. "
"The NAMELINK_SKIP option may be specified only following LIBRARY.");
@@ -564,7 +587,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
resourceArgs.HasNamelinkComponent() ||
std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
[](const cmInstallCommandFileSetArguments& fileSetArg)
- -> bool { return fileSetArg.HasNamelinkComponent(); })) {
+ -> bool { return fileSetArg.HasNamelinkComponent(); }) ||
+ cxxModuleBmiArgs.HasNamelinkComponent()) {
status.SetError(
"TARGETS given NAMELINK_COMPONENT option not in LIBRARY group. "
"The NAMELINK_COMPONENT option may be specified only following "
@@ -583,7 +607,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
!publicHeaderArgs.GetType().empty() || !resourceArgs.GetType().empty() ||
std::any_of(fileSetArgs.begin(), fileSetArgs.end(),
[](const cmInstallCommandFileSetArguments& fileSetArg)
- -> bool { return !fileSetArg.GetType().empty(); })) {
+ -> bool { return !fileSetArg.GetType().empty(); }) ||
+ !cxxModuleBmiArgs.GetType().empty()) {
status.SetError(
"TARGETS given TYPE option. The TYPE option may only be specified in "
" install(FILES) and install(DIRECTORIES).");
@@ -597,7 +622,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
}
cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr;
- if (withRuntimeDependencies) {
+ if (runtimeDependenciesArgVector) {
if (!runtimeDependencySetArg.empty()) {
status.SetError("TARGETS cannot have both RUNTIME_DEPENDENCIES and "
"RUNTIME_DEPENDENCY_SET.");
@@ -706,6 +731,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
bool installsPublicHeader = false;
bool installsResource = false;
std::vector<bool> installsFileSet(fileSetArgs.size(), false);
+ bool installsCxxModuleBmi = false;
// Generate install script code to install the given targets.
for (cmTarget* ti : targets) {
@@ -722,6 +748,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
std::unique_ptr<cmInstallFilesGenerator> publicHeaderGenerator;
std::unique_ptr<cmInstallFilesGenerator> resourceGenerator;
std::vector<std::unique_ptr<cmInstallFileSetGenerator>> fileSetGenerators;
+ std::unique_ptr<cmInstallCxxModuleBmiGenerator> cxxModuleBmiGenerator;
// Avoid selecting default destinations for PUBLIC_HEADER and
// PRIVATE_HEADER if any artifacts are specified.
@@ -760,6 +787,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
for (auto const& gen : fileSetGenerators) {
te->FileSetGenerators[gen->GetFileSet()] = gen.get();
}
+ te->CxxModuleBmiGenerator = cxxModuleBmiGenerator.get();
target.AddInstallIncludeDirectories(
*te, cmMakeRange(includesArgs.GetIncludeDirs()));
te->NamelinkOnly = namelinkOnly;
@@ -1105,6 +1133,19 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
}
}
+ if (supportCxx20FileSetTypes &&
+ !cxxModuleBmiArgs.GetDestination().empty()) {
+ cxxModuleBmiGenerator = cm::make_unique<cmInstallCxxModuleBmiGenerator>(
+ target.GetName(),
+ helper.GetCxxModulesBmiDestination(&cxxModuleBmiArgs),
+ cxxModuleBmiArgs.GetPermissions(),
+ cxxModuleBmiArgs.GetConfigurations(), cxxModuleBmiArgs.GetComponent(),
+ cmInstallGenerator::SelectMessageLevel(target.GetMakefile()),
+ cxxModuleBmiArgs.GetExcludeFromAll(), cxxModuleBmiArgs.GetOptional(),
+ helper.Makefile->GetBacktrace());
+ target.SetHaveInstallRule(true);
+ }
+
// Add this install rule to an export if one was specified.
if (!addTargetExport()) {
return false;
@@ -1121,6 +1162,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
installsPrivateHeader = installsPrivateHeader || privateHeaderGenerator;
installsPublicHeader = installsPublicHeader || publicHeaderGenerator;
installsResource = installsResource || resourceGenerator;
+ installsCxxModuleBmi = installsCxxModuleBmi || cxxModuleBmiGenerator;
helper.Makefile->AddInstallGenerator(std::move(archiveGenerator));
helper.Makefile->AddInstallGenerator(std::move(libraryGenerator));
@@ -1135,9 +1177,10 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
for (auto& gen : fileSetGenerators) {
helper.Makefile->AddInstallGenerator(std::move(gen));
}
+ helper.Makefile->AddInstallGenerator(std::move(cxxModuleBmiGenerator));
}
- if (withRuntimeDependencies && !runtimeDependencySet->Empty()) {
+ if (runtimeDependenciesArgVector && !runtimeDependencySet->Empty()) {
AddInstallRuntimeDependenciesGenerator(
helper, runtimeDependencySet, runtimeArgs, libraryArgs, frameworkArgs,
std::move(runtimeDependenciesArgs), installsRuntime, installsLibrary,
@@ -1192,6 +1235,10 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
fileSetArgs[i].GetComponent());
}
}
+ if (installsCxxModuleBmi) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ cxxModuleBmiArgs.GetComponent());
+ }
return true;
}
@@ -1206,10 +1253,10 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
struct ArgVectors
{
- std::vector<std::string> Library;
- std::vector<std::string> Runtime;
- std::vector<std::string> Framework;
- std::vector<std::string> Bundle;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Library;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Bundle;
};
static auto const argHelper = cmArgumentParser<ArgVectors>{}
@@ -1223,7 +1270,7 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
// now parse the generic args (i.e. the ones not specialized on LIBRARY,
// RUNTIME etc. (see above)
- std::vector<std::string> targetList;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> targetList;
std::string runtimeDependencySetArg;
std::vector<std::string> unknownArgs;
cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
@@ -1464,7 +1511,7 @@ bool HandleFilesMode(std::vector<std::string> const& args,
// This is the FILES mode.
bool programs = (args[0] == "PROGRAMS");
cmInstallCommandArguments ica(helper.DefaultComponentName);
- std::vector<std::string> files;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> files;
ica.Bind(programs ? "PROGRAMS"_s : "FILES"_s, files);
std::vector<std::string> unknownArgs;
ica.Parse(args, &unknownArgs);
@@ -1950,7 +1997,7 @@ bool HandleExportAndroidMKMode(std::vector<std::string> const& args,
cm::make_unique<cmInstallExportGenerator>(
&exportSet, ica.GetDestination(), ica.GetPermissions(),
ica.GetConfigurations(), ica.GetComponent(), message,
- ica.GetExcludeFromAll(), fname, name_space, exportOld, true,
+ ica.GetExcludeFromAll(), fname, name_space, "", exportOld, true,
helper.Makefile->GetBacktrace()));
return true;
@@ -1973,12 +2020,19 @@ bool HandleExportMode(std::vector<std::string> const& args,
std::string name_space;
bool exportOld = false;
std::string filename;
+ std::string cxx_modules_directory;
ica.Bind("EXPORT"_s, exp);
ica.Bind("NAMESPACE"_s, name_space);
ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld);
ica.Bind("FILE"_s, filename);
+ bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled(
+ *helper.Makefile, cmExperimental::Feature::CxxModuleCMakeApi);
+ if (supportCxx20FileSetTypes) {
+ ica.Bind("CXX_MODULES_DIRECTORY"_s, cxx_modules_directory);
+ }
+
std::vector<std::string> unknownArgs;
ica.Parse(args, &unknownArgs);
@@ -2064,8 +2118,8 @@ bool HandleExportMode(std::vector<std::string> const& args,
cm::make_unique<cmInstallExportGenerator>(
&exportSet, ica.GetDestination(), ica.GetPermissions(),
ica.GetConfigurations(), ica.GetComponent(), message,
- ica.GetExcludeFromAll(), fname, name_space, exportOld, false,
- helper.Makefile->GetBacktrace()));
+ ica.GetExcludeFromAll(), fname, name_space, cxx_modules_directory,
+ exportOld, false, helper.Makefile->GetBacktrace()));
return true;
}
@@ -2088,9 +2142,9 @@ bool HandleRuntimeDependencySetMode(std::vector<std::string> const& args,
struct ArgVectors
{
- std::vector<std::string> Library;
- std::vector<std::string> Runtime;
- std::vector<std::string> Framework;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Library;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework;
};
static auto const argHelper = cmArgumentParser<ArgVectors>{}
@@ -2106,11 +2160,9 @@ bool HandleRuntimeDependencySetMode(std::vector<std::string> const& args,
// These generic args also contain the runtime dependency set
std::string runtimeDependencySetArg;
std::vector<std::string> runtimeDependencyArgVector;
- std::vector<std::string> parsedArgs;
cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
- genericArgs.Parse(genericArgVector, &runtimeDependencyArgVector, nullptr,
- &parsedArgs);
+ genericArgs.Parse(genericArgVector, &runtimeDependencyArgVector);
bool success = genericArgs.Finalize();
cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
@@ -2280,6 +2332,15 @@ std::string Helper::GetLibraryDestination(
return this->GetDestination(args, "CMAKE_INSTALL_LIBDIR", "lib");
}
+std::string Helper::GetCxxModulesBmiDestination(
+ const cmInstallCommandArguments* args) const
+{
+ if (args) {
+ return args->GetDestination();
+ }
+ return {};
+}
+
std::string Helper::GetIncludeDestination(
const cmInstallCommandArguments* args) const
{
diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h
index 79bd945..6e46aac 100644
--- a/Source/cmInstallCommandArguments.h
+++ b/Source/cmInstallCommandArguments.h
@@ -8,6 +8,7 @@
#include <vector>
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
class cmInstallCommandArguments : public cmArgumentParser<void>
{
@@ -44,8 +45,8 @@ private:
std::string NamelinkComponent;
bool ExcludeFromAll = false;
std::string Rename;
- std::vector<std::string> Permissions;
- std::vector<std::string> Configurations;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Permissions;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Configurations;
bool Optional = false;
bool NamelinkOnly = false;
bool NamelinkSkip = false;
diff --git a/Source/cmInstallCxxModuleBmiGenerator.cxx b/Source/cmInstallCxxModuleBmiGenerator.cxx
new file mode 100644
index 0000000..1ef1eaa
--- /dev/null
+++ b/Source/cmInstallCxxModuleBmiGenerator.cxx
@@ -0,0 +1,75 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallCxxModuleBmiGenerator.h"
+
+#include <ostream>
+#include <utility>
+
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmOutputConverter.h"
+#include "cmStringAlgorithms.h"
+
+cmInstallCxxModuleBmiGenerator::cmInstallCxxModuleBmiGenerator(
+ std::string target, std::string const& dest, std::string file_permissions,
+ std::vector<std::string> const& configurations, std::string const& component,
+ MessageLevel message, bool exclude_from_all, bool optional,
+ cmListFileBacktrace backtrace)
+ : cmInstallGenerator(dest, configurations, component, message,
+ exclude_from_all, false, std::move(backtrace))
+ , TargetName(std::move(target))
+ , FilePermissions(std::move(file_permissions))
+ , Optional(optional)
+{
+ this->ActionsPerConfig = true;
+}
+
+cmInstallCxxModuleBmiGenerator::~cmInstallCxxModuleBmiGenerator() = default;
+
+bool cmInstallCxxModuleBmiGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LocalGenerator = lg;
+
+ this->Target = lg->FindLocalNonAliasGeneratorTarget(this->TargetName);
+ if (!this->Target) {
+ // If no local target has been found, find it in the global scope.
+ this->Target =
+ lg->GetGlobalGenerator()->FindGeneratorTarget(this->TargetName);
+ }
+
+ return true;
+}
+
+std::string cmInstallCxxModuleBmiGenerator::GetScriptLocation(
+ std::string const& config) const
+{
+ char const* config_name = config.c_str();
+ if (config.empty()) {
+ config_name = "noconfig";
+ }
+ return cmStrCat(this->Target->GetSupportDirectory(),
+ "/install-cxx-module-bmi-", config_name, ".cmake");
+}
+
+std::string cmInstallCxxModuleBmiGenerator::GetDestination(
+ std::string const& config) const
+{
+ return cmGeneratorExpression::Evaluate(this->Destination,
+ this->LocalGenerator, config);
+}
+
+void cmInstallCxxModuleBmiGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent indent)
+{
+ auto const& loc = this->GetScriptLocation(config);
+ if (loc.empty()) {
+ return;
+ }
+ os << indent << "include(\""
+ << cmOutputConverter::EscapeForCMake(
+ loc, cmOutputConverter::WrapQuotes::NoWrap)
+ << "\" OPTIONAL)\n";
+}
diff --git a/Source/cmInstallCxxModuleBmiGenerator.h b/Source/cmInstallCxxModuleBmiGenerator.h
new file mode 100644
index 0000000..21edb2e
--- /dev/null
+++ b/Source/cmInstallCxxModuleBmiGenerator.h
@@ -0,0 +1,52 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmInstallGenerator.h"
+#include "cmScriptGenerator.h"
+
+class cmGeneratorTarget;
+class cmListFileBacktrace;
+class cmLocalGenerator;
+
+/** \class cmInstallCxxModuleBmiGenerator
+ * \brief Generate C++ module BMI installation rules.
+ */
+class cmInstallCxxModuleBmiGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallCxxModuleBmiGenerator(
+ std::string target, std::string const& dest, std::string file_permissions,
+ std::vector<std::string> const& configurations,
+ std::string const& component, MessageLevel message, bool exclude_from_all,
+ bool optional, cmListFileBacktrace backtrace);
+ ~cmInstallCxxModuleBmiGenerator() override;
+
+ bool Compute(cmLocalGenerator* lg) override;
+
+ std::string const& GetFilePermissions() const
+ {
+ return this->FilePermissions;
+ }
+ std::string GetDestination(std::string const& config) const;
+ std::string GetScriptLocation(std::string const& config) const;
+ cmGeneratorTarget const* GetTarget() const { return this->Target; }
+ bool GetOptional() const { return this->Optional; }
+ MessageLevel GetMessageLevel() const { return this->Message; }
+
+protected:
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent indent) override;
+
+ std::string const TargetName;
+ cmGeneratorTarget const* Target = nullptr;
+ cmLocalGenerator* LocalGenerator = nullptr;
+ std::string const FilePermissions;
+ bool const Optional;
+};
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx
index 8a48aa2..1d81b0b 100644
--- a/Source/cmInstallExportGenerator.cxx
+++ b/Source/cmInstallExportGenerator.cxx
@@ -23,7 +23,8 @@ cmInstallExportGenerator::cmInstallExportGenerator(
cmExportSet* exportSet, std::string const& destination,
std::string file_permissions, std::vector<std::string> const& configurations,
std::string const& component, MessageLevel message, bool exclude_from_all,
- std::string filename, std::string name_space, bool exportOld, bool android,
+ std::string filename, std::string name_space,
+ std::string cxx_modules_directory, bool exportOld, bool android,
cmListFileBacktrace backtrace)
: cmInstallGenerator(destination, configurations, component, message,
exclude_from_all, false, std::move(backtrace))
@@ -31,6 +32,7 @@ cmInstallExportGenerator::cmInstallExportGenerator(
, FilePermissions(std::move(file_permissions))
, FileName(std::move(filename))
, Namespace(std::move(name_space))
+ , CxxModulesDirectory(std::move(cxx_modules_directory))
, ExportOld(exportOld)
{
if (android) {
@@ -48,8 +50,7 @@ cmInstallExportGenerator::~cmInstallExportGenerator() = default;
bool cmInstallExportGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
- this->ExportSet->Compute(lg);
- return true;
+ return this->ExportSet->Compute(lg);
}
std::string cmInstallExportGenerator::TempDirCalculate() const
@@ -142,6 +143,75 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
os << indent << "endif()\n";
files.clear();
}
+
+ // Now create a configuration-specific install rule for the C++ module import
+ // property file of each configuration.
+ auto cxx_module_dest =
+ cmStrCat(this->Destination, '/', this->CxxModulesDirectory);
+ std::string config_file_example;
+ for (auto const& i : this->EFGen->GetConfigCxxModuleFiles()) {
+ config_file_example = i.second;
+ break;
+ }
+ if (!config_file_example.empty()) {
+ // Remove old per-configuration export files if the main changes.
+ std::string installedDir = cmStrCat(
+ "$ENV{DESTDIR}", ConvertToAbsoluteDestination(cxx_module_dest), '/');
+ std::string installedFile = cmStrCat(installedDir, "/cxx-modules.cmake");
+ std::string toInstallFile =
+ cmStrCat(cmSystemTools::GetFilenamePath(config_file_example),
+ "/cxx-modules.cmake");
+ os << indent << "if(EXISTS \"" << installedFile << "\")\n";
+ Indent indentN = indent.Next();
+ Indent indentNN = indentN.Next();
+ Indent indentNNN = indentNN.Next();
+ /* clang-format off */
+ os << indentN << "file(DIFFERENT _cmake_export_file_changed FILES\n"
+ << indentN << " \"" << installedFile << "\"\n"
+ << indentN << " \"" << toInstallFile << "\")\n";
+ os << indentN << "if(_cmake_export_file_changed)\n";
+ os << indentNN << "file(GLOB _cmake_old_config_files \"" << installedDir
+ << this->EFGen->GetConfigImportFileGlob() << "\")\n";
+ os << indentNN << "if(_cmake_old_config_files)\n";
+ os << indentNNN << "string(REPLACE \";\" \", \" _cmake_old_config_files_text \"${_cmake_old_config_files}\")\n";
+ os << indentNNN << R"(message(STATUS "Old C++ module export file \")" << installedFile
+ << "\\\" will be replaced. Removing files [${_cmake_old_config_files_text}].\")\n";
+ os << indentNNN << "unset(_cmake_old_config_files_text)\n";
+ os << indentNNN << "file(REMOVE ${_cmake_old_config_files})\n";
+ os << indentNN << "endif()\n";
+ os << indentNN << "unset(_cmake_old_config_files)\n";
+ os << indentN << "endif()\n";
+ os << indentN << "unset(_cmake_export_file_changed)\n";
+ os << indent << "endif()\n";
+ /* clang-format on */
+
+ // All of these files are siblings; get its location to know where the
+ // "anchor" file is.
+ files.push_back(toInstallFile);
+ this->AddInstallRule(os, cxx_module_dest, cmInstallType_FILES, files,
+ false, this->FilePermissions.c_str(), nullptr,
+ nullptr, nullptr, indent);
+ files.clear();
+ }
+ for (auto const& i : this->EFGen->GetConfigCxxModuleFiles()) {
+ files.push_back(i.second);
+ std::string config_test = this->CreateConfigTest(i.first);
+ os << indent << "if(" << config_test << ")\n";
+ this->AddInstallRule(os, cxx_module_dest, cmInstallType_FILES, files,
+ false, this->FilePermissions.c_str(), nullptr,
+ nullptr, nullptr, indent.Next());
+ os << indent << "endif()\n";
+ files.clear();
+ }
+ for (auto const& i : this->EFGen->GetConfigCxxModuleTargetFiles()) {
+ std::string config_test = this->CreateConfigTest(i.first);
+ os << indent << "if(" << config_test << ")\n";
+ this->AddInstallRule(os, cxx_module_dest, cmInstallType_FILES, i.second,
+ false, this->FilePermissions.c_str(), nullptr,
+ nullptr, nullptr, indent.Next());
+ os << indent << "endif()\n";
+ files.clear();
+ }
}
void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os,
diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h
index 02fe1fa..346ca67 100644
--- a/Source/cmInstallExportGenerator.h
+++ b/Source/cmInstallExportGenerator.h
@@ -28,7 +28,8 @@ public:
const std::vector<std::string>& configurations,
std::string const& component, MessageLevel message,
bool exclude_from_all, std::string filename,
- std::string name_space, bool exportOld,
+ std::string name_space,
+ std::string cxx_modules_directory, bool exportOld,
bool android, cmListFileBacktrace backtrace);
cmInstallExportGenerator(const cmInstallExportGenerator&) = delete;
~cmInstallExportGenerator() override;
@@ -50,6 +51,10 @@ public:
std::string GetDestinationFile() const;
std::string GetFileName() const { return this->FileName; }
std::string GetTempDir() const;
+ std::string GetCxxModuleDirectory() const
+ {
+ return this->CxxModulesDirectory;
+ }
protected:
void GenerateScript(std::ostream& os) override;
@@ -64,6 +69,7 @@ protected:
std::string const FilePermissions;
std::string const FileName;
std::string const Namespace;
+ std::string const CxxModulesDirectory;
bool const ExportOld;
cmLocalGenerator* LocalGenerator = nullptr;
diff --git a/Source/cmLinkLibrariesCommand.cxx b/Source/cmLinkLibrariesCommand.cxx
index ed89e91..2b8f836 100644
--- a/Source/cmLinkLibrariesCommand.cxx
+++ b/Source/cmLinkLibrariesCommand.cxx
@@ -35,7 +35,5 @@ bool cmLinkLibrariesCommand(std::vector<std::string> const& args,
mf.AppendProperty("LINK_LIBRARIES", *i);
}
- mf.CheckProperty("LINK_LIBRARIES");
-
return true;
}
diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx
index 43f1b8e..b06dc3d 100644
--- a/Source/cmLinkLineDeviceComputer.cxx
+++ b/Source/cmLinkLineDeviceComputer.cxx
@@ -57,7 +57,6 @@ bool cmLinkLineDeviceComputer::ComputeRequiresDeviceLinking(
// For this we only consider targets
using ItemVector = cmComputeLinkInformation::ItemVector;
ItemVector const& items = cli.GetItems();
- std::string config = cli.GetConfig();
return std::any_of(
items.begin(), items.end(),
[](cmComputeLinkInformation::Item const& item) -> bool {
@@ -69,6 +68,26 @@ bool cmLinkLineDeviceComputer::ComputeRequiresDeviceLinking(
});
}
+bool cmLinkLineDeviceComputer::ComputeRequiresDeviceLinkingIPOFlag(
+ cmComputeLinkInformation& cli)
+{
+ // Determine if this item might requires device linking.
+ // For this we only consider targets
+ using ItemVector = cmComputeLinkInformation::ItemVector;
+ ItemVector const& items = cli.GetItems();
+ std::string config = cli.GetConfig();
+ return std::any_of(
+ items.begin(), items.end(),
+ [config](cmComputeLinkInformation::Item const& item) -> bool {
+ return item.Target &&
+ item.Target->GetType() == cmStateEnums::STATIC_LIBRARY &&
+ // this dependency requires us to device link it
+ !item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS") &&
+ item.Target->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION") &&
+ item.Target->IsIPOEnabled("CUDA", config);
+ });
+}
+
void cmLinkLineDeviceComputer::ComputeLinkLibraries(
cmComputeLinkInformation& cli, std::string const& stdLibString,
std::vector<BT<std::string>>& linkLibraries)
diff --git a/Source/cmLinkLineDeviceComputer.h b/Source/cmLinkLineDeviceComputer.h
index dee625b..0916307 100644
--- a/Source/cmLinkLineDeviceComputer.h
+++ b/Source/cmLinkLineDeviceComputer.h
@@ -30,6 +30,7 @@ public:
delete;
bool ComputeRequiresDeviceLinking(cmComputeLinkInformation& cli);
+ bool ComputeRequiresDeviceLinkingIPOFlag(cmComputeLinkInformation& cli);
void ComputeLinkLibraries(
cmComputeLinkInformation& cli, std::string const& stdLibString,
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index 91157cb..6270c82 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -347,6 +347,7 @@ enum class NestingStateEnum
Foreach,
Function,
Macro,
+ Block
};
struct NestingState
@@ -434,6 +435,16 @@ cm::optional<cmListFileContext> cmListFileParser::CheckNesting() const
return cmListFileContext::FromListFileFunction(func, this->FileName);
}
stack.pop_back();
+ } else if (name == "block") {
+ stack.push_back({
+ NestingStateEnum::Block,
+ cmListFileContext::FromListFileFunction(func, this->FileName),
+ });
+ } else if (name == "endblock") {
+ if (!TopIs(stack, NestingStateEnum::Block)) {
+ return cmListFileContext::FromListFileFunction(func, this->FileName);
+ }
+ stack.pop_back();
}
}
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 67c8bf2..defcba3 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -15,6 +15,7 @@
#include <vector>
#include <cm/memory>
+#include <cm/optional>
#include <cm/string_view>
#include <cmext/algorithm>
#include <cmext/string_view>
@@ -36,6 +37,7 @@
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
#include "cmLinkLineComputer.h"
+#include "cmLinkLineDeviceComputer.h"
#include "cmMakefile.h"
#include "cmRange.h"
#include "cmRulePlaceholderExpander.h"
@@ -1381,7 +1383,7 @@ std::vector<BT<std::string>> cmLocalGenerator::GetStaticLibraryFlags(
}
void cmLocalGenerator::GetDeviceLinkFlags(
- cmLinkLineComputer& linkLineComputer, const std::string& config,
+ cmLinkLineDeviceComputer& linkLineComputer, const std::string& config,
std::string& linkLibs, std::string& linkFlags, std::string& frameworkPath,
std::string& linkPath, cmGeneratorTarget* target)
{
@@ -1389,6 +1391,18 @@ void cmLocalGenerator::GetDeviceLinkFlags(
cmComputeLinkInformation* pcli = target->GetLinkInformation(config);
+ auto linklang = linkLineComputer.GetLinkerLanguage(target, config);
+ auto ipoEnabled = target->IsIPOEnabled(linklang, config);
+ if (!ipoEnabled) {
+ ipoEnabled = linkLineComputer.ComputeRequiresDeviceLinkingIPOFlag(*pcli);
+ }
+ if (ipoEnabled) {
+ if (cmValue cudaIPOFlags = this->Makefile->GetDefinition(
+ "CMAKE_CUDA_DEVICE_LINK_OPTIONS_IPO")) {
+ linkFlags += cudaIPOFlags;
+ }
+ }
+
if (pcli) {
// Compute the required device link libraries when
// resolving gpu lang device symbols
@@ -1396,6 +1410,8 @@ void cmLocalGenerator::GetDeviceLinkFlags(
linkPath);
}
+ // iterate link deps and see if any of them need IPO
+
std::vector<std::string> linkOpts;
target->GetLinkOptions(linkOpts, config, "CUDA");
// LINK_OPTIONS are escaped.
@@ -1590,7 +1606,8 @@ std::vector<BT<std::string>> cmLocalGenerator::GetTargetCompileFlags(
cmMakefile* mf = this->GetMakefile();
// Add language-specific flags.
- this->AddLanguageFlags(compileFlags, target, lang, config);
+ this->AddLanguageFlags(compileFlags, target, cmBuildStep::Compile, lang,
+ config);
if (target->IsIPOEnabled(lang, config)) {
this->AppendFeatureOptions(compileFlags, lang, "IPO");
@@ -1903,6 +1920,7 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags,
void cmLocalGenerator::AddLanguageFlags(std::string& flags,
cmGeneratorTarget const* target,
+ cmBuildStep compileOrLink,
const std::string& lang,
const std::string& config)
{
@@ -1926,7 +1944,7 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
}
}
} else if (lang == "CUDA") {
- target->AddCUDAArchitectureFlags(flags);
+ target->AddCUDAArchitectureFlags(compileOrLink, config, flags);
target->AddCUDAToolkitFlags(flags);
} else if (lang == "ISPC") {
target->AddISPCTargetFlags(flags);
@@ -2023,6 +2041,41 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
}
}
}
+
+ // Add MSVC debug information format flags. This is activated by the presence
+ // of a default selection whether or not it is overridden by a property.
+ cmValue msvcDebugInformationFormatDefault = this->Makefile->GetDefinition(
+ "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT");
+ if (cmNonempty(msvcDebugInformationFormatDefault)) {
+ cmValue msvcDebugInformationFormatValue =
+ target->GetProperty("MSVC_DEBUG_INFORMATION_FORMAT");
+ if (!msvcDebugInformationFormatValue) {
+ msvcDebugInformationFormatValue = msvcDebugInformationFormatDefault;
+ }
+ std::string const msvcDebugInformationFormat =
+ cmGeneratorExpression::Evaluate(*msvcDebugInformationFormatValue, this,
+ config, target);
+ if (!msvcDebugInformationFormat.empty()) {
+ if (cmValue msvcDebugInformationFormatOptions =
+ this->Makefile->GetDefinition(
+ cmStrCat("CMAKE_", lang,
+ "_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_",
+ msvcDebugInformationFormat))) {
+ this->AppendCompileOptions(flags, *msvcDebugInformationFormatOptions);
+ } else if ((this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_COMPILER_ID")) == "MSVC"_s ||
+ this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", lang, "_SIMULATE_ID")) == "MSVC"_s) &&
+ !cmSystemTools::GetErrorOccurredFlag()) {
+ // The compiler uses the MSVC ABI so it needs a known runtime library.
+ this->IssueMessage(MessageType::FATAL_ERROR,
+ cmStrCat("MSVC_DEBUG_INFORMATION_FORMAT value '",
+ msvcDebugInformationFormat,
+ "' not known for this ", lang,
+ " compiler."));
+ }
+ }
+ }
}
void cmLocalGenerator::AddLanguageFlagsForLinking(
@@ -2038,7 +2091,7 @@ void cmLocalGenerator::AddLanguageFlagsForLinking(
this->AddCompilerRequirementFlag(flags, target, lang, config);
}
- this->AddLanguageFlags(flags, target, lang, config);
+ this->AddLanguageFlags(flags, target, cmBuildStep::Link, lang, config);
if (target->IsIPOEnabled(lang, config)) {
this->AppendFeatureOptions(flags, lang, "IPO");
@@ -2574,7 +2627,9 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
if (pchSource.empty() || pchHeader.empty()) {
if (this->GetGlobalGenerator()->IsXcode() && !pchLangSet.empty()) {
for (auto* sf : sources) {
- if (pchLangSet.find(sf->GetLanguage()) == pchLangSet.end()) {
+ const auto sourceLanguage = sf->GetLanguage();
+ if (!sourceLanguage.empty() &&
+ pchLangSet.find(sourceLanguage) == pchLangSet.end()) {
sf->SetProperty("SKIP_PRECOMPILE_HEADERS", "ON");
}
}
@@ -2667,7 +2722,7 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
cmStrCat(linkerProperty, configUpper),
cmStrCat(" ",
this->ConvertToOutputFormat(pchSourceObj, SHELL)),
- true);
+ cm::nullopt, true);
} else if (reuseTarget->GetType() ==
cmStateEnums::OBJECT_LIBRARY) {
// FIXME: This can propagate more than one level, unlike
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 7cae1fc..0529431 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -35,6 +35,7 @@ class cmGeneratorTarget;
class cmGlobalGenerator;
class cmImplicitDependsList;
class cmLinkLineComputer;
+class cmLinkLineDeviceComputer;
class cmMakefile;
class cmRulePlaceholderExpander;
class cmSourceFile;
@@ -59,6 +60,13 @@ enum class cmDependencyScannerKind
Compiler
};
+/** What to compute language flags for */
+enum class cmBuildStep
+{
+ Compile,
+ Link
+};
+
/** Target and source file which have a specific output. */
struct cmSourcesWithOutput
{
@@ -143,7 +151,8 @@ public:
const std::string& filterArch = std::string());
void AddLanguageFlags(std::string& flags, cmGeneratorTarget const* target,
- const std::string& lang, const std::string& config);
+ cmBuildStep compileOrLink, const std::string& lang,
+ const std::string& config);
void AddLanguageFlagsForLinking(std::string& flags,
cmGeneratorTarget const* target,
const std::string& lang,
@@ -476,7 +485,7 @@ public:
/** Fill out these strings for the given target. Libraries to link,
* flags, and linkflags. */
- void GetDeviceLinkFlags(cmLinkLineComputer& linkLineComputer,
+ void GetDeviceLinkFlags(cmLinkLineDeviceComputer& linkLineComputer,
const std::string& config, std::string& linkLibs,
std::string& linkFlags, std::string& frameworkPath,
std::string& linkPath, cmGeneratorTarget* target);
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index e125470..de1d3cd 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -1412,13 +1412,16 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) {
// The dependencies must be regenerated.
- std::string targetName = cmSystemTools::GetFilenameName(targetDir);
- targetName = targetName.substr(0, targetName.length() - 4);
- std::string message =
- cmStrCat("Scanning dependencies of target ", targetName);
- cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
- cmsysTerminal_Color_ForegroundBold,
- message.c_str(), true, color);
+ if (verbose) {
+ std::string targetName = cmSystemTools::GetFilenameName(targetDir);
+ targetName = targetName.substr(0, targetName.length() - 4);
+ std::string message =
+ cmStrCat("Scanning dependencies of target ", targetName);
+ cmSystemTools::MakefileColorEcho(
+ cmsysTerminal_Color_ForegroundMagenta |
+ cmsysTerminal_Color_ForegroundBold,
+ message.c_str(), true, color);
+ }
status = this->ScanDependencies(targetDir, dependFile,
internalDependFile, validDependencies);
@@ -1447,13 +1450,19 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
this->GetBinaryDirectory())
: std::function<bool(const std::string&)>())) {
// regenerate dependencies files
- std::string targetName =
- cmCMakePath(targetDir).GetFileName().RemoveExtension().GenericString();
- auto message = cmStrCat(
- "Consolidate compiler generated dependencies of target ", targetName);
- cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
- cmsysTerminal_Color_ForegroundBold,
- message.c_str(), true, color);
+ if (verbose) {
+ std::string targetName = cmCMakePath(targetDir)
+ .GetFileName()
+ .RemoveExtension()
+ .GenericString();
+ auto message =
+ cmStrCat("Consolidate compiler generated dependencies of target ",
+ targetName);
+ cmSystemTools::MakefileColorEcho(
+ cmsysTerminal_Color_ForegroundMagenta |
+ cmsysTerminal_Color_ForegroundBold,
+ message.c_str(), true, color);
+ }
// Open the make depends file. This should be copy-if-different
// because the make tool may try to reload it needlessly otherwise.
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index f65add1..0451d96 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -680,7 +680,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
langForClCompile = linkLanguage;
if (langForClCompile == "C" || langForClCompile == "CXX" ||
langForClCompile == "Fortran") {
- this->AddLanguageFlags(flags, target, langForClCompile, configName);
+ this->AddLanguageFlags(flags, target, cmBuildStep::Compile,
+ langForClCompile, configName);
}
// set the correct language
if (linkLanguage == "C") {
diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx
index ef12487..47ad749 100644
--- a/Source/cmMacroCommand.cxx
+++ b/Source/cmMacroCommand.cxx
@@ -126,7 +126,7 @@ bool cmMacroHelperCommand::operator()(
return false;
}
if (status.GetReturnInvoked()) {
- inStatus.SetReturnInvoked();
+ inStatus.SetReturnInvoked(status.GetReturnVariables());
return true;
}
if (status.GetBreakInvoked()) {
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index c32c564..6e0d704 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -149,6 +149,29 @@ void cmMakefile::IssueMessage(MessageType t, std::string const& text) const
this->GetCMakeInstance()->IssueMessage(t, text, this->Backtrace);
}
+Message::LogLevel cmMakefile::GetCurrentLogLevel() const
+{
+ const cmake* cmakeInstance = this->GetCMakeInstance();
+
+ const Message::LogLevel logLevelCliOrDefault = cmakeInstance->GetLogLevel();
+ assert("Expected a valid log level here" &&
+ logLevelCliOrDefault != Message::LogLevel::LOG_UNDEFINED);
+
+ Message::LogLevel result = logLevelCliOrDefault;
+
+ // If the log-level was set via the command line option, it takes precedence
+ // over the CMAKE_MESSAGE_LOG_LEVEL variable.
+ if (!cmakeInstance->WasLogLevelSetViaCLI()) {
+ const Message::LogLevel logLevelFromVar = cmake::StringToLogLevel(
+ this->GetSafeDefinition("CMAKE_MESSAGE_LOG_LEVEL"));
+ if (logLevelFromVar != Message::LogLevel::LOG_UNDEFINED) {
+ result = logLevelFromVar;
+ }
+ }
+
+ return result;
+}
+
bool cmMakefile::CheckCMP0037(std::string const& targetName,
cmStateEnums::TargetType targetType) const
{
@@ -766,6 +789,7 @@ void cmMakefile::RunListFile(cmListFile const& listFile,
break;
}
if (status.GetReturnInvoked()) {
+ this->RaiseScope(status.GetReturnVariables());
// Exit early due to return command.
break;
}
@@ -3460,7 +3484,7 @@ void cmMakefile::AddTargetObject(std::string const& tgtName,
#endif
}
-void cmMakefile::EnableLanguage(std::vector<std::string> const& lang,
+void cmMakefile::EnableLanguage(std::vector<std::string> const& languages,
bool optional)
{
if (this->DeferRunning) {
@@ -3472,24 +3496,48 @@ void cmMakefile::EnableLanguage(std::vector<std::string> const& lang,
if (const char* def = this->GetGlobalGenerator()->GetCMakeCFGIntDir()) {
this->AddDefinition("CMAKE_CFG_INTDIR", def);
}
+
+ std::vector<std::string> unique_languages;
+ {
+ std::vector<std::string> duplicate_languages;
+ for (std::string const& language : languages) {
+ if (!cm::contains(unique_languages, language)) {
+ unique_languages.push_back(language);
+ } else if (!cm::contains(duplicate_languages, language)) {
+ duplicate_languages.push_back(language);
+ }
+ }
+ if (!duplicate_languages.empty()) {
+ auto quantity = duplicate_languages.size() == 1 ? std::string(" has")
+ : std::string("s have");
+ this->IssueMessage(MessageType::AUTHOR_WARNING,
+ "Languages to be enabled may not be specified more "
+ "than once at the same time. The following language" +
+ quantity + " been specified multiple times: " +
+ cmJoin(duplicate_languages, ", "));
+ }
+ }
+
// If RC is explicitly listed we need to do it after other languages.
// On some platforms we enable RC implicitly while enabling others.
// Do not let that look like recursive enable_language(RC).
- std::vector<std::string> langs;
- std::vector<std::string> langsRC;
- langs.reserve(lang.size());
- for (std::string const& i : lang) {
- if (i == "RC") {
- langsRC.push_back(i);
+ std::vector<std::string> languages_without_RC;
+ std::vector<std::string> languages_for_RC;
+ languages_without_RC.reserve(unique_languages.size());
+ for (std::string const& language : unique_languages) {
+ if (language == "RC") {
+ languages_for_RC.push_back(language);
} else {
- langs.push_back(i);
+ languages_without_RC.push_back(language);
}
}
- if (!langs.empty()) {
- this->GetGlobalGenerator()->EnableLanguage(langs, this, optional);
+ if (!languages_without_RC.empty()) {
+ this->GetGlobalGenerator()->EnableLanguage(languages_without_RC, this,
+ optional);
}
- if (!langsRC.empty()) {
- this->GetGlobalGenerator()->EnableLanguage(langsRC, this, optional);
+ if (!languages_for_RC.empty()) {
+ this->GetGlobalGenerator()->EnableLanguage(languages_for_RC, this,
+ optional);
}
}
@@ -3991,31 +4039,6 @@ std::vector<std::string> cmMakefile::GetPropertyKeys() const
return this->StateSnapshot.GetDirectory().GetPropertyKeys();
}
-void cmMakefile::CheckProperty(const std::string& prop) const
-{
- // Certain properties need checking.
- if (prop == "LINK_LIBRARIES") {
- if (cmValue value = this->GetProperty(prop)) {
- // Look for <LINK_LIBRARY:> internal pattern
- static cmsys::RegularExpression linkPattern(
- "(^|;)(</?LINK_(LIBRARY|GROUP):[^;>]*>)(;|$)");
- if (!linkPattern.find(value)) {
- return;
- }
-
- // Report an error.
- this->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("Property ", prop, " contains the invalid item \"",
- linkPattern.match(2), "\". The ", prop,
- " property may contain the generator-expression \"$<LINK_",
- linkPattern.match(3),
- ":...>\" which may be used to specify how the libraries are "
- "linked."));
- }
- }
-}
-
cmTarget* cmMakefile::FindLocalNonAliasTarget(const std::string& name) const
{
auto i = this->Targets.find(name);
@@ -4145,6 +4168,18 @@ void cmMakefile::RaiseScope(const std::string& var, const char* varDef)
#endif
}
+void cmMakefile::RaiseScope(const std::vector<std::string>& variables)
+{
+ for (auto const& varName : variables) {
+ if (this->IsNormalDefinitionSet(varName)) {
+ this->RaiseScope(varName, this->GetDefinition(varName));
+ } else {
+ // unset variable in parent scope
+ this->RaiseScope(varName, nullptr);
+ }
+ }
+}
+
cmTarget* cmMakefile::AddImportedTarget(const std::string& name,
cmStateEnums::TargetType type,
bool global)
@@ -4500,6 +4535,19 @@ bool cmMakefile::SetPolicyVersion(std::string const& version_min,
cmPolicies::WarnCompat::On);
}
+cmMakefile::VariablePushPop::VariablePushPop(cmMakefile* m)
+ : Makefile(m)
+{
+ this->Makefile->StateSnapshot =
+ this->Makefile->GetState()->CreateVariableScopeSnapshot(
+ this->Makefile->StateSnapshot);
+}
+
+cmMakefile::VariablePushPop::~VariablePushPop()
+{
+ this->Makefile->PopSnapshot();
+}
+
bool cmMakefile::HasCMP0054AlreadyBeenReported(
cmListFileContext const& context) const
{
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 2fb880f..3866aca 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -376,6 +376,20 @@ public:
};
friend class PolicyPushPop;
+ /** Helper class to push and pop variables scopes automatically. */
+ class VariablePushPop
+ {
+ public:
+ VariablePushPop(cmMakefile* m);
+ ~VariablePushPop();
+
+ VariablePushPop(VariablePushPop const&) = delete;
+ VariablePushPop& operator=(VariablePushPop const&) = delete;
+
+ private:
+ cmMakefile* Makefile;
+ };
+
/**
* Determine if the given context, name pair has already been reported
* in context of CMP0054.
@@ -794,7 +808,6 @@ public:
cmValue GetProperty(const std::string& prop, bool chain) const;
bool GetPropertyAsBool(const std::string& prop) const;
std::vector<std::string> GetPropertyKeys() const;
- void CheckProperty(const std::string& prop) const;
//! Initialize a makefile from its parent
void InitializeFromParent(cmMakefile* parent);
@@ -862,6 +875,11 @@ public:
void PushScope();
void PopScope();
void RaiseScope(const std::string& var, const char* value);
+ void RaiseScope(const std::string& var, cmValue value)
+ {
+ this->RaiseScope(var, value.GetCStr());
+ }
+ void RaiseScope(const std::vector<std::string>& variables);
// push and pop loop scopes
void PushLoopBlockBarrier();
@@ -925,6 +943,7 @@ public:
};
void IssueMessage(MessageType t, std::string const& text) const;
+ Message::LogLevel GetCurrentLogLevel() const;
/** Set whether or not to report a CMP0000 violation. */
void SetCheckCMP0000(bool b) { this->CheckCMP0000 = b; }
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index 74574f7..54f03b9 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -136,17 +136,11 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule(
std::vector<std::string> depends;
this->AppendLinkDepends(depends, linkLanguage);
- // Build a list of compiler flags and linker flags.
- std::string langFlags;
- std::string linkFlags;
-
// Add language feature flags.
+ std::string langFlags;
this->LocalGenerator->AddLanguageFlagsForLinking(
langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
- // Add device-specific linker flags.
- this->GetDeviceLinkFlags(linkFlags, linkLanguage);
-
// Construct a list of files associated with this executable that
// may need to be cleaned.
std::vector<std::string> exeCleanFiles;
@@ -173,13 +167,20 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule(
// Set path conversion for link script shells.
this->LocalGenerator->SetLinkScriptShell(useLinkScript);
- std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+ std::unique_ptr<cmLinkLineDeviceComputer> linkLineComputer(
new cmLinkLineDeviceComputer(
this->LocalGenerator,
this->LocalGenerator->GetStateSnapshot().GetDirectory()));
linkLineComputer->SetForResponse(useResponseFileForLibs);
linkLineComputer->SetRelink(relink);
+ // Create set of linking flags.
+ std::string linkFlags;
+ std::string ignored_;
+ this->LocalGenerator->GetDeviceLinkFlags(
+ *linkLineComputer, this->GetConfigName(), ignored_, linkFlags, ignored_,
+ ignored_, this->GeneratorTarget);
+
// Collect up flags to link in needed libraries.
std::string linkLibs;
this->CreateLinkLibs(
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index 3f7d87d..45ef8c8 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -287,10 +287,6 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules(
this->LocalGenerator->AddLanguageFlagsForLinking(
langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
- // Create set of linking flags.
- std::string linkFlags;
- this->GetDeviceLinkFlags(linkFlags, linkLanguage);
-
// Clean files associated with this library.
std::set<std::string> libCleanFiles;
libCleanFiles.insert(
@@ -315,13 +311,20 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules(
// Collect up flags to link in needed libraries.
std::string linkLibs;
- std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+ std::unique_ptr<cmLinkLineDeviceComputer> linkLineComputer(
new cmLinkLineDeviceComputer(
this->LocalGenerator,
this->LocalGenerator->GetStateSnapshot().GetDirectory()));
linkLineComputer->SetForResponse(useResponseFileForLibs);
linkLineComputer->SetRelink(relink);
+ // Create set of linking flags.
+ std::string linkFlags;
+ std::string ignored_;
+ this->LocalGenerator->GetDeviceLinkFlags(
+ *linkLineComputer, this->GetConfigName(), ignored_, linkFlags, ignored_,
+ ignored_, this->GeneratorTarget);
+
this->CreateLinkLibs(
linkLineComputer.get(), linkLibs, useResponseFileForLibs, depends,
cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink);
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 1e1df79..d19bbb9 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -1042,8 +1042,10 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
lang == "OBJCXX")) {
std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER";
cmValue clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
- if (cmNonempty(clauncher)) {
- compilerLauncher = *clauncher;
+ std::string evaluatedClauncher = cmGeneratorExpression::Evaluate(
+ *clauncher, this->LocalGenerator, config);
+ if (!evaluatedClauncher.empty()) {
+ compilerLauncher = evaluatedClauncher;
}
}
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
index cd57600..fa29ec9 100644
--- a/Source/cmMessageCommand.cxx
+++ b/Source/cmMessageCommand.cxx
@@ -81,94 +81,83 @@ bool cmMessageCommand(std::vector<std::string> const& args,
auto type = MessageType::MESSAGE;
auto fatal = false;
- auto level = cmake::LogLevel::LOG_UNDEFINED;
+ auto level = Message::LogLevel::LOG_UNDEFINED;
auto checkingType = CheckingType::UNDEFINED;
if (*i == "SEND_ERROR") {
type = MessageType::FATAL_ERROR;
- level = cmake::LogLevel::LOG_ERROR;
+ level = Message::LogLevel::LOG_ERROR;
++i;
} else if (*i == "FATAL_ERROR") {
fatal = true;
type = MessageType::FATAL_ERROR;
- level = cmake::LogLevel::LOG_ERROR;
+ level = Message::LogLevel::LOG_ERROR;
++i;
} else if (*i == "WARNING") {
type = MessageType::WARNING;
- level = cmake::LogLevel::LOG_WARNING;
+ level = Message::LogLevel::LOG_WARNING;
++i;
} else if (*i == "AUTHOR_WARNING") {
if (mf.IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") &&
!mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) {
fatal = true;
type = MessageType::AUTHOR_ERROR;
- level = cmake::LogLevel::LOG_ERROR;
+ level = Message::LogLevel::LOG_ERROR;
} else if (!mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
type = MessageType::AUTHOR_WARNING;
- level = cmake::LogLevel::LOG_WARNING;
+ level = Message::LogLevel::LOG_WARNING;
} else {
return true;
}
++i;
} else if (*i == "CHECK_START") {
- level = cmake::LogLevel::LOG_STATUS;
+ level = Message::LogLevel::LOG_STATUS;
checkingType = CheckingType::CHECK_START;
++i;
} else if (*i == "CHECK_PASS") {
- level = cmake::LogLevel::LOG_STATUS;
+ level = Message::LogLevel::LOG_STATUS;
checkingType = CheckingType::CHECK_PASS;
++i;
} else if (*i == "CHECK_FAIL") {
- level = cmake::LogLevel::LOG_STATUS;
+ level = Message::LogLevel::LOG_STATUS;
checkingType = CheckingType::CHECK_FAIL;
++i;
} else if (*i == "STATUS") {
- level = cmake::LogLevel::LOG_STATUS;
+ level = Message::LogLevel::LOG_STATUS;
++i;
} else if (*i == "VERBOSE") {
- level = cmake::LogLevel::LOG_VERBOSE;
+ level = Message::LogLevel::LOG_VERBOSE;
++i;
} else if (*i == "DEBUG") {
- level = cmake::LogLevel::LOG_DEBUG;
+ level = Message::LogLevel::LOG_DEBUG;
++i;
} else if (*i == "TRACE") {
- level = cmake::LogLevel::LOG_TRACE;
+ level = Message::LogLevel::LOG_TRACE;
++i;
} else if (*i == "DEPRECATION") {
if (mf.IsOn("CMAKE_ERROR_DEPRECATED")) {
fatal = true;
type = MessageType::DEPRECATION_ERROR;
- level = cmake::LogLevel::LOG_ERROR;
+ level = Message::LogLevel::LOG_ERROR;
} else if (!mf.IsSet("CMAKE_WARN_DEPRECATED") ||
mf.IsOn("CMAKE_WARN_DEPRECATED")) {
type = MessageType::DEPRECATION_WARNING;
- level = cmake::LogLevel::LOG_WARNING;
+ level = Message::LogLevel::LOG_WARNING;
} else {
return true;
}
++i;
} else if (*i == "NOTICE") {
// `NOTICE` message type is going to be output to stderr
- level = cmake::LogLevel::LOG_NOTICE;
+ level = Message::LogLevel::LOG_NOTICE;
++i;
} else {
// Messages w/o any type are `NOTICE`s
- level = cmake::LogLevel::LOG_NOTICE;
+ level = Message::LogLevel::LOG_NOTICE;
}
assert("Message log level expected to be set" &&
- level != cmake::LogLevel::LOG_UNDEFINED);
-
- auto desiredLevel = mf.GetCMakeInstance()->GetLogLevel();
- assert("Expected a valid log level here" &&
- desiredLevel != cmake::LogLevel::LOG_UNDEFINED);
-
- // Command line option takes precedence over the cache variable
- if (!mf.GetCMakeInstance()->WasLogLevelSetViaCLI()) {
- const auto desiredLevelFromCache =
- cmake::StringToLogLevel(mf.GetSafeDefinition("CMAKE_MESSAGE_LOG_LEVEL"));
- if (desiredLevelFromCache != cmake::LogLevel::LOG_UNDEFINED) {
- desiredLevel = desiredLevelFromCache;
- }
- }
+ level != Message::LogLevel::LOG_UNDEFINED);
+
+ Message::LogLevel desiredLevel = mf.GetCurrentLogLevel();
if (desiredLevel < level) {
// Suppress the message
@@ -178,17 +167,17 @@ bool cmMessageCommand(std::vector<std::string> const& args,
auto message = cmJoin(cmMakeRange(i, args.cend()), "");
switch (level) {
- case cmake::LogLevel::LOG_ERROR:
- case cmake::LogLevel::LOG_WARNING:
+ case Message::LogLevel::LOG_ERROR:
+ case Message::LogLevel::LOG_WARNING:
// we've overridden the message type, above, so display it directly
mf.GetMessenger()->DisplayMessage(type, message, mf.GetBacktrace());
break;
- case cmake::LogLevel::LOG_NOTICE:
+ case Message::LogLevel::LOG_NOTICE:
cmSystemTools::Message(IndentText(message, mf));
break;
- case cmake::LogLevel::LOG_STATUS:
+ case Message::LogLevel::LOG_STATUS:
switch (checkingType) {
case CheckingType::CHECK_START:
mf.DisplayStatus(IndentText(message, mf), -1);
@@ -209,9 +198,9 @@ bool cmMessageCommand(std::vector<std::string> const& args,
}
break;
- case cmake::LogLevel::LOG_VERBOSE:
- case cmake::LogLevel::LOG_DEBUG:
- case cmake::LogLevel::LOG_TRACE:
+ case Message::LogLevel::LOG_VERBOSE:
+ case Message::LogLevel::LOG_DEBUG:
+ case Message::LogLevel::LOG_TRACE:
mf.DisplayStatus(IndentText(message, mf), -1);
break;
diff --git a/Source/cmMessageType.h b/Source/cmMessageType.h
index 44de429..decb4b3 100644
--- a/Source/cmMessageType.h
+++ b/Source/cmMessageType.h
@@ -16,3 +16,19 @@ enum class MessageType
DEPRECATION_ERROR,
DEPRECATION_WARNING
};
+
+namespace Message {
+
+/** \brief Define log level constants. */
+enum class LogLevel
+{
+ LOG_UNDEFINED,
+ LOG_ERROR,
+ LOG_WARNING,
+ LOG_NOTICE,
+ LOG_STATUS,
+ LOG_VERBOSE,
+ LOG_DEBUG,
+ LOG_TRACE
+};
+}
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index d4f1608..bda8a5f 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -537,7 +537,6 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeDeviceLinkCmd()
// this target requires separable cuda compilation
// now build the correct command depending on if the target is
// an executable or a dynamic library.
- std::string linkCmd;
switch (this->GetGeneratorTarget()->GetType()) {
case cmStateEnums::STATIC_LIBRARY:
case cmStateEnums::SHARED_LIBRARY:
@@ -1086,10 +1085,12 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
this->GetGeneratorTarget()->GetObjectSources(sources, config);
cmLocalGenerator const* LocalGen = this->GetLocalGenerator();
for (const auto& source : sources) {
+ const std::string sourcePath = source->GetLanguage() == "Swift"
+ ? this->GetCompiledSourceNinjaPath(source)
+ : this->GetObjectFilePath(source, config);
oss << " "
- << LocalGen->ConvertToOutputFormat(
- this->GetCompiledSourceNinjaPath(source),
- cmOutputConverter::SHELL);
+ << LocalGen->ConvertToOutputFormat(sourcePath,
+ cmOutputConverter::SHELL);
}
return oss.str();
}();
@@ -1107,10 +1108,15 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
std::vector<cmSourceFile const*> sources;
gt->GetObjectSources(sources, config);
for (const auto& source : sources) {
- linkBuild.Outputs.push_back(
- this->ConvertToNinjaPath(this->GetObjectFilePath(source, config)));
- linkBuild.ExplicitDeps.emplace_back(
- this->GetCompiledSourceNinjaPath(source));
+ if (source->GetLanguage() == "Swift") {
+ linkBuild.Outputs.push_back(
+ this->ConvertToNinjaPath(this->GetObjectFilePath(source, config)));
+ linkBuild.ExplicitDeps.emplace_back(
+ this->GetCompiledSourceNinjaPath(source));
+ } else {
+ linkBuild.ExplicitDeps.emplace_back(
+ this->GetObjectFilePath(source, config));
+ }
}
linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]);
} else {
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index ee065c4..e4427f5 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -21,11 +21,17 @@
#include "cmComputeLinkInformation.h"
#include "cmCustomCommandGenerator.h"
+#include "cmExportBuildFileGenerator.h"
+#include "cmExportSet.h"
#include "cmFileSet.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalNinjaGenerator.h"
+#include "cmInstallCxxModuleBmiGenerator.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallFileSetGenerator.h"
+#include "cmInstallGenerator.h"
#include "cmLocalGenerator.h"
#include "cmLocalNinjaGenerator.h"
#include "cmMakefile.h"
@@ -41,6 +47,7 @@
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
+#include "cmTargetExport.h"
#include "cmValue.h"
#include "cmake.h"
@@ -905,8 +912,10 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
lang == "OBJCXX")) {
std::string const clauncher_prop = cmStrCat(lang, "_COMPILER_LAUNCHER");
cmValue clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
- if (cmNonempty(clauncher)) {
- compilerLauncher = *clauncher;
+ std::string evaluatedClauncher = cmGeneratorExpression::Evaluate(
+ *clauncher, this->LocalGenerator, config);
+ if (!evaluatedClauncher.empty()) {
+ compilerLauncher = evaluatedClauncher;
}
}
@@ -1336,9 +1345,11 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
}
}
- this->ExportObjectCompileCommand(
- language, sourceFilePath, objectDir, objectFileName, objectFileDir,
- vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"], config);
+ if (firstForConfig) {
+ this->ExportObjectCompileCommand(
+ language, sourceFilePath, objectDir, objectFileName, objectFileDir,
+ vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"], config);
+ }
objBuild.Outputs.push_back(objectFileName);
if (firstForConfig) {
@@ -1653,6 +1664,215 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang,
tdi_linked_target_dirs.append(l);
}
+ cmTarget* tgt = this->GeneratorTarget->Target;
+ auto all_file_sets = tgt->GetAllFileSetNames();
+ Json::Value& tdi_cxx_module_info = tdi["cxx-modules"] = Json::objectValue;
+ for (auto const& file_set_name : all_file_sets) {
+ auto* file_set = tgt->GetFileSet(file_set_name);
+ if (!file_set) {
+ this->GetMakefile()->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(),
+ "\" is tracked to have file set \"", file_set_name,
+ "\", but it was not found."));
+ continue;
+ }
+ auto fs_type = file_set->GetType();
+ // We only care about C++ module sources here.
+ if (fs_type != "CXX_MODULES"_s) {
+ continue;
+ }
+
+ auto fileEntries = file_set->CompileFileEntries();
+ auto directoryEntries = file_set->CompileDirectoryEntries();
+
+ auto directories = file_set->EvaluateDirectoryEntries(
+ directoryEntries, this->GeneratorTarget->LocalGenerator, config,
+ this->GeneratorTarget);
+ std::map<std::string, std::vector<std::string>> files_per_dirs;
+ for (auto const& entry : fileEntries) {
+ file_set->EvaluateFileEntry(directories, files_per_dirs, entry,
+ this->GeneratorTarget->LocalGenerator,
+ config, this->GeneratorTarget);
+ }
+
+ std::map<std::string, cmSourceFile const*> sf_map;
+ {
+ std::vector<cmSourceFile const*> objectSources;
+ this->GeneratorTarget->GetObjectSources(objectSources, config);
+ for (auto const* sf : objectSources) {
+ auto full_path = sf->GetFullPath();
+ if (full_path.empty()) {
+ this->GetMakefile()->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(),
+ "\" has a full path-less source file."));
+ continue;
+ }
+ sf_map[full_path] = sf;
+ }
+ }
+
+ Json::Value fs_dest = Json::nullValue;
+ for (auto const& ig : this->GetMakefile()->GetInstallGenerators()) {
+ if (auto const* fsg =
+ dynamic_cast<cmInstallFileSetGenerator const*>(ig.get())) {
+ if (fsg->GetTarget() == this->GeneratorTarget &&
+ fsg->GetFileSet() == file_set) {
+ fs_dest = fsg->GetDestination(config);
+ continue;
+ }
+ }
+ }
+
+ for (auto const& files_per_dir : files_per_dirs) {
+ for (auto const& file : files_per_dir.second) {
+ auto lookup = sf_map.find(file);
+ if (lookup == sf_map.end()) {
+ this->GetMakefile()->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
+ file,
+ R"(" which is not in any of its "FILE_SET BASE_DIRS".)"));
+ continue;
+ }
+
+ auto const* sf = lookup->second;
+
+ if (!sf) {
+ this->GetMakefile()->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
+ file, "\" which has not been tracked properly."));
+ continue;
+ }
+
+ auto obj_path = this->GetObjectFilePath(sf, config);
+ Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] =
+ Json::objectValue;
+
+ tdi_module_info["source"] = file;
+ tdi_module_info["relative-directory"] = files_per_dir.first;
+ tdi_module_info["name"] = file_set->GetName();
+ tdi_module_info["type"] = file_set->GetType();
+ tdi_module_info["visibility"] =
+ std::string(cmFileSetVisibilityToName(file_set->GetVisibility()));
+ tdi_module_info["destination"] = fs_dest;
+ }
+ }
+ }
+
+ tdi["config"] = config;
+
+ // Add information about the export sets that this target is a member of.
+ Json::Value& tdi_exports = tdi["exports"] = Json::arrayValue;
+ std::string export_name = this->GeneratorTarget->GetExportName();
+
+ cmInstallCxxModuleBmiGenerator const* bmi_gen = nullptr;
+ for (auto const& ig : this->GetMakefile()->GetInstallGenerators()) {
+ if (auto const* bmig =
+ dynamic_cast<cmInstallCxxModuleBmiGenerator const*>(ig.get())) {
+ if (bmig->GetTarget() == this->GeneratorTarget) {
+ bmi_gen = bmig;
+ continue;
+ }
+ }
+ }
+ if (bmi_gen) {
+ Json::Value tdi_bmi_info = Json::objectValue;
+
+ tdi_bmi_info["permissions"] = bmi_gen->GetFilePermissions();
+ tdi_bmi_info["destination"] = bmi_gen->GetDestination(config);
+ const char* msg_level = "";
+ switch (bmi_gen->GetMessageLevel()) {
+ case cmInstallGenerator::MessageDefault:
+ break;
+ case cmInstallGenerator::MessageAlways:
+ msg_level = "MESSAGE_ALWAYS";
+ break;
+ case cmInstallGenerator::MessageLazy:
+ msg_level = "MESSAGE_LAZY";
+ break;
+ case cmInstallGenerator::MessageNever:
+ msg_level = "MESSAGE_NEVER";
+ break;
+ }
+ tdi_bmi_info["message-level"] = msg_level;
+ tdi_bmi_info["script-location"] = bmi_gen->GetScriptLocation(config);
+
+ tdi["bmi-installation"] = tdi_bmi_info;
+ } else {
+ tdi["bmi-installation"] = Json::nullValue;
+ }
+
+ auto const& all_install_exports =
+ this->GetGlobalGenerator()->GetExportSets();
+ for (auto const& exp : all_install_exports) {
+ // Ignore exports sets which are not for this target.
+ auto const& targets = exp.second.GetTargetExports();
+ auto tgt_export =
+ std::find_if(targets.begin(), targets.end(),
+ [this](std::unique_ptr<cmTargetExport> const& te) {
+ return te->Target == this->GeneratorTarget;
+ });
+ if (tgt_export == targets.end()) {
+ continue;
+ }
+
+ auto const* installs = exp.second.GetInstallations();
+ for (auto const* install : *installs) {
+ Json::Value tdi_export_info = Json::objectValue;
+
+ auto const& ns = install->GetNamespace();
+ auto const& dest = install->GetDestination();
+ auto const& cxxm_dir = install->GetCxxModuleDirectory();
+ auto const& export_prefix = install->GetTempDir();
+
+ tdi_export_info["namespace"] = ns;
+ tdi_export_info["export-name"] = export_name;
+ tdi_export_info["destination"] = dest;
+ tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
+ tdi_export_info["export-prefix"] = export_prefix;
+ tdi_export_info["install"] = true;
+
+ tdi_exports.append(tdi_export_info);
+ }
+ }
+
+ auto const& all_build_exports =
+ this->GetMakefile()->GetExportBuildFileGenerators();
+ for (auto const& exp : all_build_exports) {
+ std::vector<std::string> targets;
+ exp->GetTargets(targets);
+
+ // Ignore exports sets which are not for this target.
+ auto const& name = this->GeneratorTarget->GetName();
+ bool has_current_target =
+ std::any_of(targets.begin(), targets.end(),
+ [name](std::string const& tname) { return tname == name; });
+ if (!has_current_target) {
+ continue;
+ }
+
+ Json::Value tdi_export_info = Json::objectValue;
+
+ auto const& ns = exp->GetNamespace();
+ auto const& main_fn = exp->GetMainExportFileName();
+ auto const& cxxm_dir = exp->GetCxxModuleDirectory();
+ auto dest = cmsys::SystemTools::GetParentDirectory(main_fn);
+ auto const& export_prefix =
+ cmSystemTools::GetFilenamePath(exp->GetMainExportFileName());
+
+ tdi_export_info["namespace"] = ns;
+ tdi_export_info["export-name"] = export_name;
+ tdi_export_info["destination"] = dest;
+ tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
+ tdi_export_info["export-prefix"] = export_prefix;
+ tdi_export_info["install"] = false;
+
+ tdi_exports.append(tdi_export_info);
+ }
+
std::string const tdin = this->GetTargetDependInfoPath(lang, config);
cmGeneratedFileStream tdif(tdin);
tdif << tdi;
diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx
index 95f3e7e..7e19566 100644
--- a/Source/cmParseArgumentsCommand.cxx
+++ b/Source/cmParseArgumentsCommand.cxx
@@ -10,6 +10,7 @@
#include <cm/string_view>
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
@@ -41,11 +42,18 @@ namespace {
using options_map = std::map<std::string, bool>;
using single_map = std::map<std::string, std::string>;
-using multi_map = std::map<std::string, std::vector<std::string>>;
-using options_set = std::set<std::string>;
+using multi_map =
+ std::map<std::string, ArgumentParser::NonEmpty<std::vector<std::string>>>;
+using options_set = std::set<cm::string_view>;
struct UserArgumentParser : public cmArgumentParser<void>
{
+ void BindKeywordsMissingValue(std::vector<cm::string_view>& ref)
+ {
+ this->cmArgumentParser<void>::BindKeywordMissingValue(
+ [&ref](Instance&, cm::string_view arg) { ref.emplace_back(arg); });
+ }
+
template <typename T, typename H>
void Bind(std::vector<std::string> const& names,
std::map<std::string, T>& ref, H duplicateKey)
@@ -208,9 +216,10 @@ bool cmParseArgumentsCommand(std::vector<std::string> const& args,
}
}
- std::vector<std::string> keywordsMissingValues;
+ std::vector<cm::string_view> keywordsMissingValues;
+ parser.BindKeywordsMissingValue(keywordsMissingValues);
- parser.Parse(list, &unparsed, &keywordsMissingValues);
+ parser.Parse(list, &unparsed);
PassParsedArguments(
prefix, status.GetMakefile(), options, singleValArgs, multiValArgs,
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index cb7402c..4643868 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -421,7 +421,17 @@ class cmMakefile;
SELECT( \
POLICY, CMP0139, \
"The if() command supports path comparisons using PATH_EQUAL operator.", \
- 3, 24, 0, cmPolicies::WARN)
+ 3, 24, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0140, "The return() command checks its arguments.", 3, \
+ 25, 0, cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0141, \
+ "MSVC debug information format flags are selected by an abstraction.", 3, \
+ 25, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0142, \
+ "The Xcode generator does not append per-config suffixes to " \
+ "library search paths.", \
+ 3, 25, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
@@ -458,7 +468,8 @@ class cmMakefile;
F(CMP0112) \
F(CMP0113) \
F(CMP0119) \
- F(CMP0131)
+ F(CMP0131) \
+ F(CMP0142)
/** \class cmPolicies
* \brief Handles changes in CMake behavior and policies
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 40f3ab5..6c500b0 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -1847,8 +1847,7 @@ void cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName,
void cmQtAutoGenInitializer::AddCleanFile(std::string const& fileName)
{
- this->GenTarget->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", fileName,
- false);
+ this->GenTarget->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", fileName);
}
void cmQtAutoGenInitializer::ConfigFileNames(ConfigString& configString,
diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx
index a7125b1..4753e61 100644
--- a/Source/cmQtAutoMocUic.cxx
+++ b/Source/cmQtAutoMocUic.cxx
@@ -2167,6 +2167,8 @@ void cmQtAutoMocUicT::JobCompileUicT::Process()
void cmQtAutoMocUicT::JobMocsCompilationT::Process()
{
+ std::string const& compAbs = this->MocConst().CompFileAbs;
+
// Compose mocs compilation file content
std::string content =
"// This file is autogenerated. Changes will be overwritten.\n";
@@ -2175,14 +2177,7 @@ void cmQtAutoMocUicT::JobMocsCompilationT::Process()
// Placeholder content
content += "// No files found that require moc or the moc files are "
"included\n"
- "struct cmake_automoc_silence_linker_warning{\n"
- " virtual ~cmake_automoc_silence_linker_warning();\n"
- "};\n"
- "\n"
- "inline "
- "cmake_automoc_silence_linker_warning::"
- "~cmake_automoc_silence_linker_warning()\n"
- "{}\n";
+ "enum some_compilers { need_more_than_nothing };\n";
} else {
// Valid content
const bool mc = this->BaseConst().MultiConfig;
@@ -2191,7 +2186,6 @@ void cmQtAutoMocUicT::JobMocsCompilationT::Process()
content += cmWrap(wrapFront, this->MocEval().CompFiles, wrapBack, "");
}
- std::string const& compAbs = this->MocConst().CompFileAbs;
if (cmQtAutoGenerator::FileDiffers(compAbs, content)) {
// Actually write mocs compilation file
if (this->Log().Verbose()) {
diff --git a/Source/cmReturnCommand.cxx b/Source/cmReturnCommand.cxx
index 5905669..765b772 100644
--- a/Source/cmReturnCommand.cxx
+++ b/Source/cmReturnCommand.cxx
@@ -2,12 +2,52 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmReturnCommand.h"
+#include <cm/string_view>
+#include <cmext/string_view>
+
#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
// cmReturnCommand
-bool cmReturnCommand(std::vector<std::string> const&,
+bool cmReturnCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- status.SetReturnInvoked();
+ if (!args.empty()) {
+ switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0140)) {
+ case cmPolicies::WARN:
+ status.GetMakefile().IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0140), '\n',
+ "return() checks its arguments when the policy is set to NEW. "
+ "Since the policy is not set the OLD behavior will be used so "
+ "the arguments will be ignored."));
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ return true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat('\n', cmPolicies::GetPolicyWarning(cmPolicies::CMP0140)));
+ cmSystemTools::SetFatalErrorOccurred();
+ return false;
+ default:
+ break;
+ }
+ if (args[0] != "PROPAGATE"_s) {
+ status.SetError(
+ cmStrCat("called with unsupported argument \"", args[0], '"'));
+ cmSystemTools::SetFatalErrorOccurred();
+ return false;
+ }
+ status.SetReturnInvoked({ args.begin() + 1, args.end() });
+ } else {
+ status.SetReturnInvoked();
+ }
return true;
}
diff --git a/Source/cmScanDepFormat.cxx b/Source/cmScanDepFormat.cxx
index 82a374a..ec53af5 100644
--- a/Source/cmScanDepFormat.cxx
+++ b/Source/cmScanDepFormat.cxx
@@ -5,6 +5,7 @@
#include <cctype>
#include <cstdio>
+#include <iostream>
#include <utility>
#include <cm/optional>
@@ -188,6 +189,19 @@ bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp,
return false;
}
+ if (provide.isMember("is-interface")) {
+ Json::Value const& is_interface = provide["is-interface"];
+ if (!is_interface.isBool()) {
+ cmSystemTools::Error(
+ cmStrCat("-E cmake_ninja_dyndep failed to parse ", arg_pp,
+ ": is-interface is not a boolean"));
+ return false;
+ }
+ provide_info.IsInterface = is_interface.asBool();
+ } else {
+ provide_info.IsInterface = true;
+ }
+
info->Provides.push_back(provide_info);
}
}
@@ -267,6 +281,27 @@ bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp,
info->Requires.push_back(require_info);
}
}
+
+ // MSVC 17.3 toolchain bug. Remove when 17.4 is available.
+ if (rule.isMember("is-interface")) {
+ std::cerr
+ << "warning: acknowledging an VS 17.3 toolchain bug; accepting "
+ "until a new release which fixes it is available"
+ << std::endl;
+
+ Json::Value const& is_interface_json = rule["is-interface"];
+ if (!is_interface_json.isBool()) {
+ cmSystemTools::Error(
+ cmStrCat("-E cmake_ninja_dyndep failed to parse ", arg_pp,
+ ": is-interface is not a boolean"));
+ return false;
+ }
+ bool is_interface = is_interface_json.asBool();
+
+ for (auto& provide : info->Provides) {
+ provide.IsInterface = is_interface;
+ }
+ }
}
}
@@ -308,6 +343,8 @@ bool cmScanDepFormat_P1689_Write(std::string const& path,
provide_obj["source-path"] = EncodeFilename(provide.SourcePath);
}
+ provide_obj["is-interface"] = provide.IsInterface;
+
provides.append(provide_obj);
}
diff --git a/Source/cmScanDepFormat.h b/Source/cmScanDepFormat.h
index dae28d9..dc55bf1 100644
--- a/Source/cmScanDepFormat.h
+++ b/Source/cmScanDepFormat.h
@@ -18,6 +18,11 @@ struct cmSourceReqInfo
std::string SourcePath;
std::string CompiledModulePath;
bool UseSourcePath = false;
+
+ // Provides-only fields.
+ bool IsInterface = true;
+
+ // Requires-only fields.
LookupMethod Method = LookupMethod::ByName;
};
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
index db10cd4..521cf63 100644
--- a/Source/cmSetPropertyCommand.cxx
+++ b/Source/cmSetPropertyCommand.cxx
@@ -9,6 +9,7 @@
#include "cmExecutionStatus.h"
#include "cmGlobalGenerator.h"
#include "cmInstalledFile.h"
+#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
@@ -561,7 +562,8 @@ bool HandleTarget(cmTarget* target, cmMakefile& makefile,
{
// Set or append the property.
if (appendMode) {
- target->AppendProperty(propertyName, propertyValue, appendAsString);
+ target->AppendProperty(propertyName, propertyValue,
+ makefile.GetBacktrace(), appendAsString);
} else {
if (remove) {
target->SetProperty(propertyName, nullptr);
diff --git a/Source/cmSourceGroup.cxx b/Source/cmSourceGroup.cxx
index 155068cb..6019de1 100644
--- a/Source/cmSourceGroup.cxx
+++ b/Source/cmSourceGroup.cxx
@@ -124,6 +124,21 @@ cmSourceGroup* cmSourceGroup::MatchChildrenFiles(const std::string& name)
return nullptr;
}
+const cmSourceGroup* cmSourceGroup::MatchChildrenFiles(
+ const std::string& name) const
+{
+ if (this->MatchesFiles(name)) {
+ return this;
+ }
+ for (const cmSourceGroup& group : this->Internal->GroupChildren) {
+ const cmSourceGroup* result = group.MatchChildrenFiles(name);
+ if (result) {
+ return result;
+ }
+ }
+ return nullptr;
+}
+
cmSourceGroup* cmSourceGroup::MatchChildrenRegex(const std::string& name)
{
for (cmSourceGroup& group : this->Internal->GroupChildren) {
diff --git a/Source/cmSourceGroup.h b/Source/cmSourceGroup.h
index 295240d..9ce71c7 100644
--- a/Source/cmSourceGroup.h
+++ b/Source/cmSourceGroup.h
@@ -80,6 +80,12 @@ public:
cmSourceGroup* MatchChildrenFiles(const std::string& name);
/**
+ * Check if the given name matches this group's explicit file list
+ * in children.
+ */
+ const cmSourceGroup* MatchChildrenFiles(const std::string& name) const;
+
+ /**
* Check if the given name matches this group's regex in children.
*/
cmSourceGroup* MatchChildrenRegex(const std::string& name);
diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx
index 785f356..d2eac0c 100644
--- a/Source/cmStandardLevelResolver.cxx
+++ b/Source/cmStandardLevelResolver.cxx
@@ -18,6 +18,7 @@
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
@@ -378,25 +379,29 @@ std::unordered_map<std::string, StandardLevelComputer>
"C", std::vector<int>{ 90, 99, 11, 17, 23 },
std::vector<std::string>{ "90", "99", "11", "17", "23" } } },
{ "CXX",
- StandardLevelComputer{
- "CXX", std::vector<int>{ 98, 11, 14, 17, 20, 23 },
- std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } },
+ StandardLevelComputer{ "CXX",
+ std::vector<int>{ 98, 11, 14, 17, 20, 23, 26 },
+ std::vector<std::string>{ "98", "11", "14", "17",
+ "20", "23", "26" } } },
{ "CUDA",
- StandardLevelComputer{
- "CUDA", std::vector<int>{ 03, 11, 14, 17, 20, 23 },
- std::vector<std::string>{ "03", "11", "14", "17", "20", "23" } } },
+ StandardLevelComputer{ "CUDA",
+ std::vector<int>{ 03, 11, 14, 17, 20, 23, 26 },
+ std::vector<std::string>{ "03", "11", "14", "17",
+ "20", "23", "26" } } },
{ "OBJC",
StandardLevelComputer{
"OBJC", std::vector<int>{ 90, 99, 11, 17, 23 },
std::vector<std::string>{ "90", "99", "11", "17", "23" } } },
{ "OBJCXX",
- StandardLevelComputer{
- "OBJCXX", std::vector<int>{ 98, 11, 14, 17, 20, 23 },
- std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } },
+ StandardLevelComputer{ "OBJCXX",
+ std::vector<int>{ 98, 11, 14, 17, 20, 23, 26 },
+ std::vector<std::string>{ "98", "11", "14", "17",
+ "20", "23", "26" } } },
{ "HIP",
- StandardLevelComputer{
- "HIP", std::vector<int>{ 98, 11, 14, 17, 20, 23 },
- std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } }
+ StandardLevelComputer{ "HIP",
+ std::vector<int>{ 98, 11, 14, 17, 20, 23, 26 },
+ std::vector<std::string>{ "98", "11", "14", "17",
+ "20", "23", "26" } } }
};
}
@@ -416,7 +421,8 @@ bool cmStandardLevelResolver::AddRequiredTargetFeature(
cmTarget* target, const std::string& feature, std::string* error) const
{
if (cmGeneratorExpression::Find(feature) != std::string::npos) {
- target->AppendProperty("COMPILE_FEATURES", feature);
+ target->AppendProperty("COMPILE_FEATURES", feature,
+ this->Makefile->GetBacktrace());
return true;
}
@@ -426,7 +432,8 @@ bool cmStandardLevelResolver::AddRequiredTargetFeature(
return false;
}
- target->AppendProperty("COMPILE_FEATURES", feature);
+ target->AppendProperty("COMPILE_FEATURES", feature,
+ this->Makefile->GetBacktrace());
// FIXME: Add a policy to avoid updating the <LANG>_STANDARD target
// property due to COMPILE_FEATURES. The language standard selection
diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx
index f73df8f..c51650a 100644
--- a/Source/cmStateSnapshot.cxx
+++ b/Source/cmStateSnapshot.cxx
@@ -317,6 +317,25 @@ void cmStateSnapshot::SetDefaultDefinitions()
this->SetDefinition("CMAKE_HOST_SOLARIS", "1");
#endif
+#if defined(__OpenBSD__)
+ this->SetDefinition("BSD", "OpenBSD");
+ this->SetDefinition("CMAKE_HOST_BSD", "OpenBSD");
+#elif defined(__FreeBSD__)
+ this->SetDefinition("BSD", "FreeBSD");
+ this->SetDefinition("CMAKE_HOST_BSD", "FreeBSD");
+#elif defined(__NetBSD__)
+ this->SetDefinition("BSD", "NetBSD");
+ this->SetDefinition("CMAKE_HOST_BSD", "NetBSD");
+#elif defined(__DragonFly__)
+ this->SetDefinition("BSD", "DragonFlyBSD");
+ this->SetDefinition("CMAKE_HOST_BSD", "DragonFlyBSD");
+#endif
+
+#if defined(__linux__)
+ this->SetDefinition("LINUX", "1");
+ this->SetDefinition("CMAKE_HOST_LINUX", "1");
+#endif
+
this->SetDefinition("CMAKE_MAJOR_VERSION",
std::to_string(cmVersion::GetMajorVersion()));
this->SetDefinition("CMAKE_MINOR_VERSION",
diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx
index 1bb6808..f73c854 100644
--- a/Source/cmStringAlgorithms.cxx
+++ b/Source/cmStringAlgorithms.cxx
@@ -250,6 +250,38 @@ bool cmStrToULong(std::string const& str, unsigned long* value)
return cmStrToULong(str.c_str(), value);
}
+bool cmStrToLongLong(const char* str, long long* value)
+{
+ errno = 0;
+ char* endp;
+ *value = strtoll(str, &endp, 10);
+ return (*endp == '\0') && (endp != str) && (errno == 0);
+}
+
+bool cmStrToLongLong(std::string const& str, long long* value)
+{
+ return cmStrToLongLong(str.c_str(), value);
+}
+
+bool cmStrToULongLong(const char* str, unsigned long long* value)
+{
+ errno = 0;
+ char* endp;
+ while (cmIsSpace(*str)) {
+ ++str;
+ }
+ if (*str == '-') {
+ return false;
+ }
+ *value = strtoull(str, &endp, 10);
+ return (*endp == '\0') && (endp != str) && (errno == 0);
+}
+
+bool cmStrToULongLong(std::string const& str, unsigned long long* value)
+{
+ return cmStrToULongLong(str.c_str(), value);
+}
+
template <typename Range>
std::size_t getJoinedLength(Range const& rng, cm::string_view separator)
{
diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h
index 492e588..83938bc 100644
--- a/Source/cmStringAlgorithms.h
+++ b/Source/cmStringAlgorithms.h
@@ -303,3 +303,13 @@ bool cmStrToLong(std::string const& str, long* value);
* integer */
bool cmStrToULong(const char* str, unsigned long* value);
bool cmStrToULong(std::string const& str, unsigned long* value);
+
+/** Converts a string to long long. Expects that the whole string
+ * is an integer */
+bool cmStrToLongLong(const char* str, long long* value);
+bool cmStrToLongLong(std::string const& str, long long* value);
+
+/** Converts a string to unsigned long long. Expects that the whole string
+ * is an integer */
+bool cmStrToULongLong(const char* str, unsigned long long* value);
+bool cmStrToULongLong(std::string const& str, unsigned long long* value);
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index fe311d1..c12d1fe 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -1014,7 +1014,7 @@ int ParseIndex(
Json::ArrayIndex index = static_cast<Json::ArrayIndex>(lindex);
if (index >= max) {
cmAlphaNum sizeStr{ max };
- throw json_error({ "expected an index less then "_s, sizeStr.View(),
+ throw json_error({ "expected an index less than "_s, sizeStr.View(),
" got '"_s, str, "'"_s },
progress);
}
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 55b0df8..5737cc1 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -11,11 +11,17 @@
// NOLINTNEXTLINE(bugprone-reserved-identifier)
# define _XOPEN_SOURCE 700
#endif
+#if defined(__APPLE__)
+// Restore Darwin APIs removed by _POSIX_C_SOURCE.
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
+# define _DARWIN_C_SOURCE
+#endif
#include "cmSystemTools.h"
#include <cm/optional>
#include <cmext/algorithm>
+#include <cmext/string_view>
#include <cm3p/uv.h>
@@ -87,7 +93,6 @@
# include <unistd.h>
# include <sys/time.h>
-# include <sys/types.h>
#endif
#if defined(_WIN32) && \
@@ -107,6 +112,10 @@
# include <sys/utsname.h>
#endif
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+# define CM_WINDOWS_DEPRECATED_GetVersionEx
+#endif
+
namespace {
cmSystemTools::InterruptCallback s_InterruptCallback;
@@ -904,6 +913,40 @@ cmSystemTools::WindowsFileRetry cmSystemTools::GetWindowsDirectoryRetry()
InitWindowsDirectoryRetry().Retry;
return retry;
}
+
+cmSystemTools::WindowsVersion cmSystemTools::GetWindowsVersion()
+{
+ /* Windows version number data. */
+ OSVERSIONINFOEXW osviex;
+ ZeroMemory(&osviex, sizeof(osviex));
+ osviex.dwOSVersionInfoSize = sizeof(osviex);
+
+# ifdef CM_WINDOWS_DEPRECATED_GetVersionEx
+# pragma warning(push)
+# ifdef __INTEL_COMPILER
+# pragma warning(disable : 1478)
+# elif defined __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
+# else
+# pragma warning(disable : 4996)
+# endif
+# endif
+ GetVersionExW((OSVERSIONINFOW*)&osviex);
+# ifdef CM_WINDOWS_DEPRECATED_GetVersionEx
+# ifdef __clang__
+# pragma clang diagnostic pop
+# else
+# pragma warning(pop)
+# endif
+# endif
+
+ WindowsVersion result;
+ result.dwMajorVersion = osviex.dwMajorVersion;
+ result.dwMinorVersion = osviex.dwMinorVersion;
+ result.dwBuildNumber = osviex.dwBuildNumber;
+ return result;
+}
#endif
std::string cmSystemTools::GetRealPathResolvingWindowsSubst(
@@ -962,6 +1005,93 @@ void cmSystemTools::InitializeLibUV()
#endif
}
+#if defined(_WIN32)
+# include <random>
+
+# include <wctype.h>
+# ifdef _MSC_VER
+using mode_t = cmSystemTools::SystemTools::mode_t;
+# endif
+#else
+# include <sys/stat.h>
+#endif
+
+inline int Mkdir(const char* dir, const mode_t* mode)
+{
+#if defined(_WIN32)
+ int ret = _wmkdir(cmSystemTools::ConvertToWindowsExtendedPath(dir).c_str());
+ if (ret == 0 && mode)
+ cmSystemTools::SystemTools::SetPermissions(dir, *mode);
+ return ret;
+#else
+ return mkdir(dir, mode ? *mode : 0777);
+#endif
+}
+
+cmsys::Status cmSystemTools::MakeTempDirectory(std::string& path,
+ const mode_t* mode)
+{
+ if (path.empty()) {
+ return cmsys::Status::POSIX(EINVAL);
+ }
+ return cmSystemTools::MakeTempDirectory(&path.front(), mode);
+}
+
+cmsys::Status cmSystemTools::MakeTempDirectory(char* path, const mode_t* mode)
+{
+ if (!path) {
+ return cmsys::Status::POSIX(EINVAL);
+ }
+
+ // verify that path ends with "XXXXXX"
+ const auto l = std::strlen(path);
+ if (!cmHasLiteralSuffix(cm::string_view{ path, l }, "XXXXXX")) {
+ return cmsys::Status::POSIX(EINVAL);
+ }
+
+ // create parent directories
+ auto* sep = path;
+ while ((sep = strchr(sep, '/'))) {
+ // all underlying functions use C strings,
+ // so temporarily end the string here
+ *sep = '\0';
+ Mkdir(path, mode);
+
+ *sep = '/';
+ ++sep;
+ }
+
+#ifdef _WIN32
+ const int nchars = 36;
+ const char chars[nchars + 1] = "abcdefghijklmnopqrstuvwxyz0123456789";
+
+ std::random_device rd;
+ std::mt19937 rg{ rd() };
+ std::uniform_int_distribution<int> dist{ 0, nchars - 1 };
+
+ for (auto tries = 100; tries; --tries) {
+ for (auto n = l - 6; n < l; ++n) {
+ path[n] = chars[dist(rg)];
+ }
+ if (Mkdir(path, mode) == 0) {
+ return cmsys::Status::Success();
+ } else if (errno != EEXIST) {
+ return cmsys::Status::POSIX_errno();
+ }
+ }
+ return cmsys::Status::POSIX(EAGAIN);
+#else
+ if (mkdtemp(path)) {
+ if (mode) {
+ chmod(path, *mode);
+ }
+ } else {
+ return cmsys::Status::POSIX_errno();
+ }
+ return cmsys::Status::Success();
+#endif
+}
+
#ifdef _WIN32
namespace {
bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname,
@@ -1501,8 +1631,7 @@ std::string cmSystemTools::RelativeIfUnder(std::string const& top,
bool cmSystemTools::UnsetEnv(const char* value)
{
# if !defined(HAVE_UNSETENV)
- std::string var = cmStrCat(value, '=');
- return cmSystemTools::PutEnv(var);
+ return cmSystemTools::UnPutEnv(value);
# else
unsetenv(value);
return true;
@@ -1513,9 +1642,18 @@ std::vector<std::string> cmSystemTools::GetEnvironmentVariables()
{
std::vector<std::string> env;
int cc;
+# ifdef _WIN32
+ // if program starts with main, _wenviron is initially NULL, call to
+ // _wgetenv and create wide-character string environment
+ _wgetenv(L"");
+ for (cc = 0; _wenviron[cc]; ++cc) {
+ env.emplace_back(cmsys::Encoding::ToNarrow(_wenviron[cc]));
+ }
+# else
for (cc = 0; environ[cc]; ++cc) {
env.emplace_back(environ[cc]);
}
+# endif
return env;
}
@@ -1526,6 +1664,144 @@ void cmSystemTools::AppendEnv(std::vector<std::string> const& env)
}
}
+void cmSystemTools::EnvDiff::AppendEnv(std::vector<std::string> const& env)
+{
+ for (std::string const& eit : env) {
+ this->PutEnv(eit);
+ }
+}
+
+void cmSystemTools::EnvDiff::PutEnv(const std::string& env)
+{
+ auto const eq_loc = env.find('=');
+ if (eq_loc != std::string::npos) {
+ std::string name = env.substr(0, eq_loc);
+ diff[name] = env.substr(eq_loc + 1);
+ } else {
+ this->UnPutEnv(env);
+ }
+}
+
+void cmSystemTools::EnvDiff::UnPutEnv(const std::string& env)
+{
+ diff[env] = {};
+}
+
+bool cmSystemTools::EnvDiff::ParseOperation(const std::string& envmod)
+{
+ char path_sep = GetSystemPathlistSeparator();
+
+ auto apply_diff = [this](const std::string& name,
+ std::function<void(std::string&)> const& apply) {
+ cm::optional<std::string> old_value = diff[name];
+ std::string output;
+ if (old_value) {
+ output = *old_value;
+ } else {
+ const char* curval = cmSystemTools::GetEnv(name);
+ if (curval) {
+ output = curval;
+ }
+ }
+ apply(output);
+ diff[name] = output;
+ };
+
+ // Split on `=`
+ auto const eq_loc = envmod.find_first_of('=');
+ if (eq_loc == std::string::npos) {
+ cmSystemTools::Error(cmStrCat(
+ "Error: Missing `=` after the variable name in: ", envmod, '\n'));
+ return false;
+ }
+
+ auto const name = envmod.substr(0, eq_loc);
+
+ // Split value on `:`
+ auto const op_value_start = eq_loc + 1;
+ auto const colon_loc = envmod.find_first_of(':', op_value_start);
+ if (colon_loc == std::string::npos) {
+ cmSystemTools::Error(
+ cmStrCat("Error: Missing `:` after the operation in: ", envmod, '\n'));
+ return false;
+ }
+ auto const op = envmod.substr(op_value_start, colon_loc - op_value_start);
+
+ auto const value_start = colon_loc + 1;
+ auto const value = envmod.substr(value_start);
+
+ // Determine what to do with the operation.
+ if (op == "reset"_s) {
+ auto entry = diff.find(name);
+ if (entry != diff.end()) {
+ diff.erase(entry);
+ }
+ } else if (op == "set"_s) {
+ diff[name] = value;
+ } else if (op == "unset"_s) {
+ diff[name] = {};
+ } else if (op == "string_append"_s) {
+ apply_diff(name, [&value](std::string& output) { output += value; });
+ } else if (op == "string_prepend"_s) {
+ apply_diff(name,
+ [&value](std::string& output) { output.insert(0, value); });
+ } else if (op == "path_list_append"_s) {
+ apply_diff(name, [&value, path_sep](std::string& output) {
+ if (!output.empty()) {
+ output += path_sep;
+ }
+ output += value;
+ });
+ } else if (op == "path_list_prepend"_s) {
+ apply_diff(name, [&value, path_sep](std::string& output) {
+ if (!output.empty()) {
+ output.insert(output.begin(), path_sep);
+ }
+ output.insert(0, value);
+ });
+ } else if (op == "cmake_list_append"_s) {
+ apply_diff(name, [&value](std::string& output) {
+ if (!output.empty()) {
+ output += ';';
+ }
+ output += value;
+ });
+ } else if (op == "cmake_list_prepend"_s) {
+ apply_diff(name, [&value](std::string& output) {
+ if (!output.empty()) {
+ output.insert(output.begin(), ';');
+ }
+ output.insert(0, value);
+ });
+ } else {
+ cmSystemTools::Error(cmStrCat(
+ "Error: Unrecognized environment manipulation argument: ", op, '\n'));
+ return false;
+ }
+
+ return true;
+}
+
+void cmSystemTools::EnvDiff::ApplyToCurrentEnv(std::ostringstream* measurement)
+{
+ for (auto const& env_apply : diff) {
+ if (env_apply.second) {
+ auto const env_update =
+ cmStrCat(env_apply.first, '=', *env_apply.second);
+ cmSystemTools::PutEnv(env_update);
+ if (measurement) {
+ *measurement << env_update << std::endl;
+ }
+ } else {
+ cmSystemTools::UnsetEnv(env_apply.first.c_str());
+ if (measurement) {
+ // Signify that this variable is being actively unset
+ *measurement << '#' << env_apply.first << "=\n";
+ }
+ }
+ }
+}
+
cmSystemTools::SaveRestoreEnvironment::SaveRestoreEnvironment()
{
this->Env = cmSystemTools::GetEnvironmentVariables();
@@ -3320,22 +3596,12 @@ cmsys::Status cmSystemTools::CreateSymlink(std::string const& origName,
uv_fs_t req;
int flags = 0;
#if defined(_WIN32)
- bool const isDir = cmsys::SystemTools::FileIsDirectory(origName);
- if (isDir) {
- flags |= UV_FS_SYMLINK_JUNCTION;
+ if (cmsys::SystemTools::FileIsDirectory(origName)) {
+ flags |= UV_FS_SYMLINK_DIR;
}
#endif
int err = uv_fs_symlink(nullptr, &req, origName.c_str(), newName.c_str(),
flags, nullptr);
-#if defined(_WIN32)
- if (err && uv_fs_get_system_error(&req) == ERROR_NOT_SUPPORTED && isDir) {
- // Try fallback to symlink for network (requires additional permissions).
- flags ^= UV_FS_SYMLINK_JUNCTION | UV_FS_SYMLINK_DIR;
- err = uv_fs_symlink(nullptr, &req, origName.c_str(), newName.c_str(),
- flags, nullptr);
- }
-#endif
-
cmsys::Status status;
if (err) {
#if defined(_WIN32)
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 5f7a5ec..b02a977 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -4,11 +4,18 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#if !defined(_WIN32)
+# include <sys/types.h>
+#endif
+
#include <cstddef>
#include <functional>
+#include <map>
+#include <sstream>
#include <string>
#include <vector>
+#include <cm/optional>
#include <cm/string_view>
#include "cmsys/Process.h"
@@ -148,6 +155,27 @@ public:
Failure,
};
+#if defined(_MSC_VER)
+ /** Visual C++ does not define mode_t. */
+ using mode_t = unsigned short;
+#endif
+
+ /**
+ * Make a new temporary directory. The path must end in "XXXXXX", and will
+ * be modified to reflect the name of the directory created. This function
+ * is similar to POSIX mkdtemp (and is implemented using the same where that
+ * function is available).
+ *
+ * This function can make a full path even if none of the directories existed
+ * prior to calling this function.
+ *
+ * Note that this function may modify \p path even if it does not succeed.
+ */
+ static cmsys::Status MakeTempDirectory(char* path,
+ const mode_t* mode = nullptr);
+ static cmsys::Status MakeTempDirectory(std::string& path,
+ const mode_t* mode = nullptr);
+
/** Copy a file. */
static bool CopySingleFile(const std::string& oldname,
const std::string& newname);
@@ -377,6 +405,42 @@ public:
/** Append multiple variables to the current environment. */
static void AppendEnv(std::vector<std::string> const& env);
+ /**
+ * Helper class to represent an environment diff directly. This is to avoid
+ * repeated in-place environment modification (i.e. via setenv/putenv), which
+ * could be slow.
+ */
+ class EnvDiff
+ {
+ public:
+ /** Append multiple variables to the current environment diff */
+ void AppendEnv(std::vector<std::string> const& env);
+
+ /**
+ * Add a single variable (or remove if no = sign) to the current
+ * environment diff.
+ */
+ void PutEnv(const std::string& env);
+
+ /** Remove a single variable from the current environment diff. */
+ void UnPutEnv(const std::string& env);
+
+ /**
+ * Apply an ENVIRONMENT_MODIFICATION operation to this diff. Returns
+ * false and issues an error on parse failure.
+ */
+ bool ParseOperation(const std::string& envmod);
+
+ /**
+ * Apply this diff to the actual environment, optionally writing out the
+ * modifications to a CTest-compatible measurement stream.
+ */
+ void ApplyToCurrentEnv(std::ostringstream* measurement = nullptr);
+
+ private:
+ std::map<std::string, cm::optional<std::string>> diff;
+ };
+
/** Helper class to save and restore the environment.
Instantiate this class as an automatic variable on
the stack. Its constructor saves a copy of the current
@@ -509,6 +573,14 @@ public:
};
static WindowsFileRetry GetWindowsFileRetry();
static WindowsFileRetry GetWindowsDirectoryRetry();
+
+ struct WindowsVersion
+ {
+ unsigned int dwMajorVersion;
+ unsigned int dwMinorVersion;
+ unsigned int dwBuildNumber;
+ };
+ static WindowsVersion GetWindowsVersion();
#endif
/** Get the real path for a given path, removing all symlinks.
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 4df6681..874195b 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -295,6 +295,12 @@ public:
cm::string_view fileSetType) const;
cmValue GetFileSetPaths(cmTarget const* self, std::string const& fileSetName,
cm::string_view fileSetType) const;
+
+ cmListFileBacktrace GetBacktrace(
+ cm::optional<cmListFileBacktrace> const& bt) const
+ {
+ return bt ? *bt : this->Makefile->GetBacktrace();
+ }
};
cmTargetInternals::cmTargetInternals()
@@ -557,6 +563,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
initProp("AUTORCC_OPTIONS");
initProp("LINK_DEPENDS_NO_SHARED");
initProp("LINK_INTERFACE_LIBRARIES");
+ initProp("MSVC_DEBUG_INFORMATION_FORMAT");
initProp("MSVC_RUNTIME_LIBRARY");
initProp("WATCOM_RUNTIME_LIBRARY");
initProp("WIN32_EXECUTABLE");
@@ -620,6 +627,9 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
initProp("XCODE_SCHEME_THREAD_SANITIZER_STOP");
initProp("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER");
initProp("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP");
+ initProp("XCODE_SCHEME_LAUNCH_CONFIGURATION");
+ initProp("XCODE_SCHEME_ENABLE_GPU_API_VALIDATION");
+ initProp("XCODE_SCHEME_ENABLE_GPU_SHADER_VALIDATION");
initProp("XCODE_SCHEME_WORKING_DIRECTORY");
initProp("XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER");
initProp("XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP");
@@ -1243,7 +1253,8 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
? targetNameGenex(lib)
: lib;
this->AppendProperty("LINK_LIBRARIES",
- this->GetDebugGeneratorExpressions(libName, llt));
+ this->GetDebugGeneratorExpressions(libName, llt),
+ mf.GetBacktrace());
}
if (cmGeneratorExpression::Find(lib) != std::string::npos ||
@@ -1684,7 +1695,9 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value)
}
void cmTarget::AppendProperty(const std::string& prop,
- const std::string& value, bool asString)
+ const std::string& value,
+ cm::optional<cmListFileBacktrace> const& bt,
+ bool asString)
{
if (prop == "NAME") {
this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
@@ -1715,32 +1728,32 @@ void cmTarget::AppendProperty(const std::string& prop,
}
if (prop == "INCLUDE_DIRECTORIES") {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->IncludeDirectoriesEntries.emplace_back(value, lfbt);
}
} else if (prop == "COMPILE_OPTIONS") {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->CompileOptionsEntries.emplace_back(value, lfbt);
}
} else if (prop == "COMPILE_FEATURES") {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->CompileFeaturesEntries.emplace_back(value, lfbt);
}
} else if (prop == "COMPILE_DEFINITIONS") {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->CompileDefinitionsEntries.emplace_back(value, lfbt);
}
} else if (prop == "LINK_OPTIONS") {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->LinkOptionsEntries.emplace_back(value, lfbt);
}
} else if (prop == "LINK_DIRECTORIES") {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->LinkDirectoriesEntries.emplace_back(value, lfbt);
}
} else if (prop == "PRECOMPILE_HEADERS") {
@@ -1753,32 +1766,32 @@ void cmTarget::AppendProperty(const std::string& prop,
return;
}
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->PrecompileHeadersEntries.emplace_back(value, lfbt);
}
} else if (prop == "LINK_LIBRARIES") {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->LinkImplementationPropertyEntries.emplace_back(value, lfbt);
}
} else if (prop == propINTERFACE_LINK_LIBRARIES) {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->LinkInterfacePropertyEntries.emplace_back(value, lfbt);
}
} else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT) {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->LinkInterfaceDirectPropertyEntries.emplace_back(value, lfbt);
}
} else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE) {
if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->LinkInterfaceDirectExcludePropertyEntries.emplace_back(value,
lfbt);
}
} else if (prop == "SOURCES") {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+ cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
this->impl->SourceEntries.emplace_back(value, lfbt);
} else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME")) {
this->impl->Makefile->IssueMessage(
@@ -1935,6 +1948,97 @@ void cmTarget::AppendBuildInterfaceIncludes()
}
}
+namespace {
+bool CheckLinkLibraryPattern(cm::string_view property,
+ const std::vector<BT<std::string>>& value,
+ cmake* context)
+{
+ // Look for <LINK_LIBRARY:> and </LINK_LIBRARY:> internal tags
+ static cmsys::RegularExpression linkPattern(
+ "(^|;)(</?LINK_(LIBRARY|GROUP):[^;>]*>)(;|$)");
+
+ bool isValid = true;
+
+ for (const auto& item : value) {
+ if (!linkPattern.find(item.Value)) {
+ continue;
+ }
+
+ isValid = false;
+
+ // Report an error.
+ context->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(
+ "Property ", property, " contains the invalid item \"",
+ linkPattern.match(2), "\". The ", property,
+ " property may contain the generator-expression \"$<LINK_",
+ linkPattern.match(3),
+ ":...>\" which may be used to specify how the libraries are linked."),
+ item.Backtrace);
+ }
+
+ return isValid;
+}
+}
+
+void cmTarget::FinalizeTargetConfiguration(
+ const cmBTStringRange& noConfigCompileDefinitions,
+ cm::optional<std::map<std::string, cmValue>>& perConfigCompileDefinitions)
+{
+ if (this->GetType() == cmStateEnums::GLOBAL_TARGET) {
+ return;
+ }
+
+ if (!CheckLinkLibraryPattern("LINK_LIBRARIES"_s,
+ this->impl->LinkImplementationPropertyEntries,
+ this->GetMakefile()->GetCMakeInstance()) ||
+ !CheckLinkLibraryPattern("INTERFACE_LINK_LIBRARIES"_s,
+ this->impl->LinkInterfacePropertyEntries,
+ this->GetMakefile()->GetCMakeInstance()) ||
+ !CheckLinkLibraryPattern("INTERFACE_LINK_LIBRARIES_DIRECT"_s,
+ this->impl->LinkInterfaceDirectPropertyEntries,
+ this->GetMakefile()->GetCMakeInstance())) {
+ return;
+ }
+
+ this->AppendBuildInterfaceIncludes();
+
+ if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ return;
+ }
+
+ for (auto const& def : noConfigCompileDefinitions) {
+ this->InsertCompileDefinition(def);
+ }
+
+ auto* mf = this->GetMakefile();
+ cmPolicies::PolicyStatus polSt = mf->GetPolicyStatus(cmPolicies::CMP0043);
+ if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
+ if (perConfigCompileDefinitions) {
+ for (auto const& it : *perConfigCompileDefinitions) {
+ if (cmValue val = it.second) {
+ this->AppendProperty(it.first, *val);
+ }
+ }
+ } else {
+ perConfigCompileDefinitions.emplace();
+ std::vector<std::string> configs =
+ mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
+
+ for (std::string const& c : configs) {
+ std::string defPropName =
+ cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(c));
+ cmValue val = mf->GetProperty(defPropName);
+ (*perConfigCompileDefinitions)[defPropName] = val;
+ if (val) {
+ this->AppendProperty(defPropName, *val);
+ }
+ }
+ }
+ }
+}
+
void cmTarget::InsertInclude(BT<std::string> const& entry, bool before)
{
auto position = before ? this->impl->IncludeDirectoriesEntries.begin()
@@ -1978,27 +2082,6 @@ void cmTarget::InsertPrecompileHeader(BT<std::string> const& entry)
}
namespace {
-void CheckLinkLibraryPattern(const std::string& property,
- const std::string& value, cmMakefile* context)
-{
- // Look for <LINK_LIBRARY:> and </LINK_LIBRARY:> internal tags
- static cmsys::RegularExpression linkPattern(
- "(^|;)(</?LINK_(LIBRARY|GROUP):[^;>]*>)(;|$)");
- if (!linkPattern.find(value)) {
- return;
- }
-
- // Report an error.
- context->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat(
- "Property ", property, " contains the invalid item \"",
- linkPattern.match(2), "\". The ", property,
- " property may contain the generator-expression \"$<LINK_",
- linkPattern.match(3),
- ":...>\" which may be used to specify how the libraries are linked."));
-}
-
void CheckLINK_INTERFACE_LIBRARIES(const std::string& prop,
const std::string& value,
cmMakefile* context, bool imported)
@@ -2033,13 +2116,6 @@ void CheckLINK_INTERFACE_LIBRARIES(const std::string& prop,
}
context->IssueMessage(MessageType::FATAL_ERROR, e.str());
}
-
- CheckLinkLibraryPattern(base, value, context);
-}
-
-void CheckLINK_LIBRARIES(const std::string& value, cmMakefile* context)
-{
- CheckLinkLibraryPattern("LINK_LIBRARIES", value, context);
}
void CheckINTERFACE_LINK_LIBRARIES(const std::string& value,
@@ -2060,8 +2136,6 @@ void CheckINTERFACE_LINK_LIBRARIES(const std::string& value,
context->IssueMessage(MessageType::FATAL_ERROR, e.str());
}
-
- CheckLinkLibraryPattern("INTERFACE_LINK_LIBRARIES", value, context);
}
void CheckIMPORTED_GLOBAL(const cmTarget* target, cmMakefile* context)
@@ -2094,10 +2168,6 @@ void cmTarget::CheckProperty(const std::string& prop,
if (cmValue value = this->GetProperty(prop)) {
CheckLINK_INTERFACE_LIBRARIES(prop, *value, context, true);
}
- } else if (prop == "LINK_LIBRARIES") {
- if (cmValue value = this->GetProperty(prop)) {
- CheckLINK_LIBRARIES(*value, context);
- }
} else if (prop == "INTERFACE_LINK_LIBRARIES") {
if (cmValue value = this->GetProperty(prop)) {
CheckINTERFACE_LINK_LIBRARIES(*value, context);
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 94d6688..38bd036 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -5,12 +5,15 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <iosfwd>
+#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
+#include <cm/optional>
+
#include "cmAlgorithms.h"
#include "cmFileSet.h"
#include "cmPolicies.h"
@@ -182,8 +185,10 @@ public:
{
this->SetProperty(prop, cmValue(value));
}
- void AppendProperty(const std::string& prop, const std::string& value,
- bool asString = false);
+ void AppendProperty(
+ const std::string& prop, const std::string& value,
+ cm::optional<cmListFileBacktrace> const& bt = cm::nullopt,
+ bool asString = false);
//! Might return a nullptr if the property is not set or invalid
cmValue GetProperty(const std::string& prop) const;
//! Always returns a valid pointer
@@ -233,6 +238,9 @@ public:
void InsertPrecompileHeader(BT<std::string> const& entry);
void AppendBuildInterfaceIncludes();
+ void FinalizeTargetConfiguration(
+ const cmBTStringRange& noConfigCompileDefinitions,
+ cm::optional<std::map<std::string, cmValue>>& perConfigCompileDefinitions);
std::string GetDebugGeneratorExpressions(const std::string& value,
cmTargetLinkLibraryType llt) const;
diff --git a/Source/cmTargetCompileDefinitionsCommand.cxx b/Source/cmTargetCompileDefinitionsCommand.cxx
index b56b245..268bfac 100644
--- a/Source/cmTargetCompileDefinitionsCommand.cxx
+++ b/Source/cmTargetCompileDefinitionsCommand.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTargetCompileDefinitionsCommand.h"
+#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmStringAlgorithms.h"
@@ -28,7 +29,8 @@ private:
const std::vector<std::string>& content,
bool /*prepend*/, bool /*system*/) override
{
- tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content));
+ tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content),
+ this->Makefile->GetBacktrace());
return true; // Successfully handled.
}
diff --git a/Source/cmTargetExport.h b/Source/cmTargetExport.h
index 885ac74..1cef888 100644
--- a/Source/cmTargetExport.h
+++ b/Source/cmTargetExport.h
@@ -8,6 +8,7 @@
class cmFileSet;
class cmGeneratorTarget;
+class cmInstallCxxModuleBmiGenerator;
class cmInstallFileSetGenerator;
class cmInstallFilesGenerator;
class cmInstallTargetGenerator;
@@ -32,6 +33,7 @@ public:
cmInstallTargetGenerator* BundleGenerator;
cmInstallFilesGenerator* HeaderGenerator;
std::map<cmFileSet*, cmInstallFileSetGenerator*> FileSetGenerators;
+ cmInstallCxxModuleBmiGenerator* CxxModuleBmiGenerator;
///@}
bool NamelinkOnly = false;
diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx
index b4b4319..cb83873 100644
--- a/Source/cmTargetIncludeDirectoriesCommand.cxx
+++ b/Source/cmTargetIncludeDirectoriesCommand.cxx
@@ -88,7 +88,8 @@ void TargetIncludeDirectoriesImpl::HandleInterfaceContent(
system);
if (system) {
std::string joined = this->Join(content);
- tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", joined);
+ tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", joined,
+ this->Makefile->GetBacktrace());
}
}
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index ba901d0..0b123b2 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -379,9 +379,6 @@ bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args,
target->SetProperty("LINK_INTERFACE_LIBRARIES", "");
}
- target->CheckProperty("LINK_LIBRARIES", &mf);
- target->CheckProperty("INTERFACE_LINK_LIBRARIES", &mf);
-
return true;
}
@@ -625,7 +622,7 @@ bool TLL::HandleLibrary(ProcessingState currentProcessingState,
void TLL::AppendProperty(std::string const& prop, std::string const& value)
{
this->AffectsProperty(prop);
- this->Target->AppendProperty(prop, value);
+ this->Target->AppendProperty(prop, value, this->Makefile.GetBacktrace());
}
void TLL::AffectsProperty(std::string const& prop)
@@ -636,14 +633,16 @@ void TLL::AffectsProperty(std::string const& prop)
// Add a wrapper to the expression to tell LookupLinkItem to look up
// names in the caller's directory.
if (this->Props.insert(prop).second) {
- this->Target->AppendProperty(prop, this->DirectoryId);
+ this->Target->AppendProperty(prop, this->DirectoryId,
+ this->Makefile.GetBacktrace());
}
}
TLL::~TLL()
{
for (std::string const& prop : this->Props) {
- this->Target->AppendProperty(prop, CMAKE_DIRECTORY_ID_SEP);
+ this->Target->AppendProperty(prop, CMAKE_DIRECTORY_ID_SEP,
+ this->Makefile.GetBacktrace());
}
}
diff --git a/Source/cmTargetPrecompileHeadersCommand.cxx b/Source/cmTargetPrecompileHeadersCommand.cxx
index a5066cc..4dd158d 100644
--- a/Source/cmTargetPrecompileHeadersCommand.cxx
+++ b/Source/cmTargetPrecompileHeadersCommand.cxx
@@ -5,6 +5,7 @@
#include <utility>
#include "cmGeneratorExpression.h"
+#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmStringAlgorithms.h"
@@ -48,7 +49,8 @@ private:
{
std::string const& base = this->Makefile->GetCurrentSourceDirectory();
tgt->AppendProperty("PRECOMPILE_HEADERS",
- this->Join(ConvertToAbsoluteContent(content, base)));
+ this->Join(ConvertToAbsoluteContent(content, base)),
+ this->Makefile->GetBacktrace());
return true;
}
diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx
index e4244a6..53e25b5 100644
--- a/Source/cmTargetSourcesCommand.cxx
+++ b/Source/cmTargetSourcesCommand.cxx
@@ -9,6 +9,7 @@
#include <cmext/string_view>
#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
#include "cmExperimental.h"
#include "cmFileSet.h"
#include "cmGeneratorExpression.h"
@@ -28,8 +29,8 @@ struct FileSetArgs
{
std::string Type;
std::string FileSet;
- std::vector<std::string> BaseDirs;
- std::vector<std::string> Files;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> BaseDirs;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Files;
};
auto const FileSetArgsParser = cmArgumentParser<FileSetArgs>()
@@ -78,7 +79,8 @@ private:
{
tgt->AppendProperty("SOURCES",
this->Join(this->ConvertToAbsoluteContent(
- tgt, content, IsInterface::No, CheckCMP0076::Yes)));
+ tgt, content, IsInterface::No, CheckCMP0076::Yes)),
+ this->Makefile->GetBacktrace());
return true; // Successfully handled.
}
@@ -197,7 +199,7 @@ std::vector<std::string> TargetSourcesImpl::ConvertToAbsoluteContent(
bool TargetSourcesImpl::HandleFileSetMode(
const std::string& scope, const std::vector<std::string>& content)
{
- auto args = FileSetsArgsParser.Parse(content);
+ auto args = FileSetsArgsParser.Parse(content, /*unparsedArguments=*/nullptr);
for (auto& argList : args.FileSets) {
argList.emplace(argList.begin(), "FILE_SET"_s);
@@ -269,7 +271,8 @@ bool TargetSourcesImpl::HandleOneFileSet(
}
if (cmFileSetVisibilityIsForInterface(visibility) &&
- !cmFileSetVisibilityIsForSelf(visibility)) {
+ !cmFileSetVisibilityIsForSelf(visibility) &&
+ !this->Target->IsImported()) {
if (type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s) {
this->SetError(
R"(File set TYPEs "CXX_MODULES" and "CXX_MODULE_HEADER_UNITS" may not have "INTERFACE" visibility)");
@@ -322,11 +325,13 @@ bool TargetSourcesImpl::HandleOneFileSet(
cmStrCat("$<BUILD_INTERFACE:", dir, ">");
if (cmFileSetVisibilityIsForSelf(visibility)) {
this->Target->AppendProperty("INCLUDE_DIRECTORIES",
- interfaceDirectoriesGenex);
+ interfaceDirectoriesGenex,
+ this->Makefile->GetBacktrace());
}
if (cmFileSetVisibilityIsForInterface(visibility)) {
this->Target->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
- interfaceDirectoriesGenex);
+ interfaceDirectoriesGenex,
+ this->Makefile->GetBacktrace());
}
}
}
diff --git a/Source/cmTryCompileCommand.cxx b/Source/cmTryCompileCommand.cxx
index 130c228..a2c4ce1 100644
--- a/Source/cmTryCompileCommand.cxx
+++ b/Source/cmTryCompileCommand.cxx
@@ -2,34 +2,69 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTryCompileCommand.h"
+#include "cmCoreTryCompile.h"
+#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmRange.h"
+#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmValue.h"
#include "cmake.h"
-class cmExecutionStatus;
-
-// cmTryCompileCommand
-bool cmTryCompileCommand::InitialPass(std::vector<std::string> const& argv,
- cmExecutionStatus&)
+bool cmTryCompileCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
{
- if (argv.size() < 3) {
+ cmMakefile& mf = status.GetMakefile();
+
+ if (args.size() < 3) {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "The try_compile() command requires at least 3 arguments.");
return false;
}
- if (this->Makefile->GetCMakeInstance()->GetWorkingMode() ==
- cmake::FIND_PACKAGE_MODE) {
- this->Makefile->IssueMessage(
+ if (mf.GetCMakeInstance()->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
+ mf.IssueMessage(
MessageType::FATAL_ERROR,
"The try_compile() command is not supported in --find-package mode.");
return false;
}
- this->TryCompileCode(argv, false);
+ cmStateEnums::TargetType targetType = cmStateEnums::EXECUTABLE;
+ cmValue tt = mf.GetDefinition("CMAKE_TRY_COMPILE_TARGET_TYPE");
+ if (cmNonempty(tt)) {
+ if (*tt == cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE)) {
+ targetType = cmStateEnums::EXECUTABLE;
+ } else if (*tt ==
+ cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY)) {
+ targetType = cmStateEnums::STATIC_LIBRARY;
+ } else {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Invalid value '", *tt,
+ "' for CMAKE_TRY_COMPILE_TARGET_TYPE. Only '",
+ cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE),
+ "' and '",
+ cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY),
+ "' are allowed."));
+ return false;
+ }
+ }
+
+ cmCoreTryCompile tc(&mf);
+ cmCoreTryCompile::Arguments arguments =
+ tc.ParseArgs(cmMakeRange(args), false);
+ if (!arguments) {
+ return true;
+ }
+ tc.TryCompileCode(arguments, targetType);
// if They specified clean then we clean up what we can
- if (this->SrcFileSignature) {
- if (!this->Makefile->GetCMakeInstance()->GetDebugTryCompile()) {
- this->CleanupFiles(this->BinaryDirectory);
+ if (tc.SrcFileSignature) {
+ if (!mf.GetCMakeInstance()->GetDebugTryCompile()) {
+ tc.CleanupFiles(tc.BinaryDirectory);
}
}
return true;
diff --git a/Source/cmTryCompileCommand.h b/Source/cmTryCompileCommand.h
index d8cc16e..6a3430b 100644
--- a/Source/cmTryCompileCommand.h
+++ b/Source/cmTryCompileCommand.h
@@ -7,33 +7,7 @@
#include <string>
#include <vector>
-#include <cm/memory>
-
-#include "cmCommand.h"
-#include "cmCoreTryCompile.h"
-
class cmExecutionStatus;
-/** \class cmTryCompileCommand
- * \brief Specifies where to install some files
- *
- * cmTryCompileCommand is used to test if source code can be compiled
- */
-class cmTryCompileCommand : public cmCoreTryCompile
-{
-public:
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- return cm::make_unique<cmTryCompileCommand>();
- }
-
- /**
- * This is called when the command is first encountered in
- * the CMakeLists.txt file.
- */
- bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status) override;
-};
+bool cmTryCompileCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx
index c82ac64..70c7cf1 100644
--- a/Source/cmTryRunCommand.cxx
+++ b/Source/cmTryRunCommand.cxx
@@ -4,9 +4,14 @@
#include <cstdio>
+#include <cm/optional>
+
#include "cmsys/FStream.hxx"
+#include "cmArgumentParserTypes.h"
+#include "cmCoreTryCompile.h"
#include "cmDuration.h"
+#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmRange.h"
@@ -17,157 +22,155 @@
#include "cmValue.h"
#include "cmake.h"
-class cmExecutionStatus;
+namespace {
-// cmTryRunCommand
-bool cmTryRunCommand::InitialPass(std::vector<std::string> const& argv,
- cmExecutionStatus&)
+class TryRunCommandImpl : public cmCoreTryCompile
{
- if (argv.size() < 4) {
- return false;
+public:
+ TryRunCommandImpl(cmMakefile* mf)
+ : cmCoreTryCompile(mf)
+ {
}
- if (this->Makefile->GetCMakeInstance()->GetWorkingMode() ==
- cmake::FIND_PACKAGE_MODE) {
- this->Makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- "The try_run() command is not supported in --find-package mode.");
- return false;
- }
+ bool TryRunCode(std::vector<std::string> const& args);
- // build an arg list for TryCompile and extract the runArgs,
- std::vector<std::string> tryCompile;
-
- this->CompileResultVariable.clear();
- this->RunResultVariable.clear();
- this->OutputVariable.clear();
- this->RunOutputVariable.clear();
- this->CompileOutputVariable.clear();
-
- std::string runArgs;
- unsigned int i;
- for (i = 1; i < argv.size(); ++i) {
- if (argv[i] == "ARGS") {
- ++i;
- while (i < argv.size() && argv[i] != "COMPILE_DEFINITIONS" &&
- argv[i] != "CMAKE_FLAGS" && argv[i] != "LINK_OPTIONS" &&
- argv[i] != "LINK_LIBRARIES") {
- runArgs += " ";
- runArgs += argv[i];
- ++i;
- }
- if (i < argv.size()) {
- tryCompile.push_back(argv[i]);
- }
- } else {
- if (argv[i] == "OUTPUT_VARIABLE") {
- if (argv.size() <= (i + 1)) {
- cmSystemTools::Error(
- "OUTPUT_VARIABLE specified but there is no variable");
- return false;
- }
- i++;
- this->OutputVariable = argv[i];
- } else if (argv[i] == "RUN_OUTPUT_VARIABLE") {
- if (argv.size() <= (i + 1)) {
- cmSystemTools::Error(
- "RUN_OUTPUT_VARIABLE specified but there is no variable");
- return false;
- }
- i++;
- this->RunOutputVariable = argv[i];
- } else if (argv[i] == "COMPILE_OUTPUT_VARIABLE") {
- if (argv.size() <= (i + 1)) {
- cmSystemTools::Error(
- "COMPILE_OUTPUT_VARIABLE specified but there is no variable");
- return false;
- }
- i++;
- this->CompileOutputVariable = argv[i];
- } else if (argv[i] == "WORKING_DIRECTORY") {
- if (argv.size() <= (i + 1)) {
- cmSystemTools::Error(
- "WORKING_DIRECTORY specified but there is no variable");
- return false;
- }
- i++;
- this->WorkingDirectory = argv[i];
- } else {
- tryCompile.push_back(argv[i]);
- }
- }
+ void RunExecutable(const std::string& runArgs,
+ cm::optional<std::string> const& workDir,
+ std::string* runOutputContents,
+ std::string* runOutputStdOutContents,
+ std::string* runOutputStdErrContents);
+ void DoNotRunExecutable(const std::string& runArgs,
+ const std::string& srcFile,
+ std::string const& compileResultVariable,
+ std::string* runOutputContents,
+ std::string* runOutputStdOutContents,
+ std::string* runOutputStdErrContents);
+
+ std::string RunResultVariable;
+};
+
+bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
+{
+ this->RunResultVariable = argv[0];
+ cmCoreTryCompile::Arguments arguments =
+ this->ParseArgs(cmMakeRange(argv).advance(1), true);
+ if (!arguments) {
+ return true;
}
// although they could be used together, don't allow it, because
// using OUTPUT_VARIABLE makes crosscompiling harder
- if (!this->OutputVariable.empty() &&
- (!this->RunOutputVariable.empty() ||
- !this->CompileOutputVariable.empty())) {
+ if (arguments.OutputVariable &&
+ (arguments.CompileOutputVariable || arguments.RunOutputVariable ||
+ arguments.RunOutputStdOutVariable ||
+ arguments.RunOutputStdErrVariable)) {
cmSystemTools::Error(
"You cannot use OUTPUT_VARIABLE together with COMPILE_OUTPUT_VARIABLE "
- "or RUN_OUTPUT_VARIABLE. Please use only COMPILE_OUTPUT_VARIABLE and/or "
- "RUN_OUTPUT_VARIABLE.");
+ ", RUN_OUTPUT_VARIABLE, RUN_OUTPUT_STDOUT_VARIABLE or "
+ "RUN_OUTPUT_STDERR_VARIABLE. "
+ "Please use only COMPILE_OUTPUT_VARIABLE, RUN_OUTPUT_VARIABLE, "
+ "RUN_OUTPUT_STDOUT_VARIABLE "
+ "and/or RUN_OUTPUT_STDERR_VARIABLE.");
return false;
}
- if (!this->WorkingDirectory.empty()) {
- if (!cmSystemTools::MakeDirectory(this->WorkingDirectory)) {
+ if ((arguments.RunOutputStdOutVariable ||
+ arguments.RunOutputStdErrVariable) &&
+ arguments.RunOutputVariable) {
+ cmSystemTools::Error(
+ "You cannot use RUN_OUTPUT_STDOUT_VARIABLE or "
+ "RUN_OUTPUT_STDERR_VARIABLE together "
+ "with RUN_OUTPUT_VARIABLE. Please use only COMPILE_OUTPUT_VARIABLE or "
+ "RUN_OUTPUT_STDOUT_VARIABLE and/or RUN_OUTPUT_STDERR_VARIABLE.");
+ return false;
+ }
+
+ if (arguments.RunWorkingDirectory) {
+ if (!cmSystemTools::MakeDirectory(*arguments.RunWorkingDirectory)) {
cmSystemTools::Error(cmStrCat("Error creating working directory \"",
- this->WorkingDirectory, "\"."));
+ *arguments.RunWorkingDirectory, "\"."));
return false;
}
}
bool captureRunOutput = false;
- if (!this->OutputVariable.empty()) {
+ bool captureRunOutputStdOutErr = false;
+ if (arguments.OutputVariable) {
captureRunOutput = true;
- tryCompile.emplace_back("OUTPUT_VARIABLE");
- tryCompile.push_back(this->OutputVariable);
- }
- if (!this->CompileOutputVariable.empty()) {
- tryCompile.emplace_back("OUTPUT_VARIABLE");
- tryCompile.push_back(this->CompileOutputVariable);
+ } else if (arguments.CompileOutputVariable) {
+ arguments.OutputVariable = arguments.CompileOutputVariable;
}
- if (!this->RunOutputVariable.empty()) {
+ if (arguments.RunOutputStdOutVariable || arguments.RunOutputStdErrVariable) {
+ captureRunOutputStdOutErr = true;
+ } else if (arguments.RunOutputVariable) {
captureRunOutput = true;
}
- this->RunResultVariable = argv[0];
- this->CompileResultVariable = argv[1];
-
// do the try compile
- int res = this->TryCompileCode(tryCompile, true);
+ bool compiled = this->TryCompileCode(arguments, cmStateEnums::EXECUTABLE);
// now try running the command if it compiled
- if (!res) {
+ if (compiled) {
if (this->OutputFile.empty()) {
cmSystemTools::Error(this->FindErrorMessage);
} else {
+ std::string runArgs;
+ if (arguments.RunArgs) {
+ runArgs = cmStrCat(" ", cmJoin(*arguments.RunArgs, " "));
+ }
+
// "run" it and capture the output
std::string runOutputContents;
+ std::string runOutputStdOutContents;
+ std::string runOutputStdErrContents;
if (this->Makefile->IsOn("CMAKE_CROSSCOMPILING") &&
!this->Makefile->IsDefinitionSet("CMAKE_CROSSCOMPILING_EMULATOR")) {
this->DoNotRunExecutable(
- runArgs, argv[3], captureRunOutput ? &runOutputContents : nullptr);
+ runArgs, *arguments.SourceDirectoryOrFile,
+ *arguments.CompileResultVariable,
+ captureRunOutput ? &runOutputContents : nullptr,
+ captureRunOutputStdOutErr && arguments.RunOutputStdOutVariable
+ ? &runOutputStdOutContents
+ : nullptr,
+ captureRunOutputStdOutErr && arguments.RunOutputStdErrVariable
+ ? &runOutputStdErrContents
+ : nullptr);
} else {
- this->RunExecutable(runArgs, &runOutputContents);
+ this->RunExecutable(
+ runArgs, arguments.RunWorkingDirectory,
+ captureRunOutput ? &runOutputContents : nullptr,
+ captureRunOutputStdOutErr && arguments.RunOutputStdOutVariable
+ ? &runOutputStdOutContents
+ : nullptr,
+ captureRunOutputStdOutErr && arguments.RunOutputStdErrVariable
+ ? &runOutputStdErrContents
+ : nullptr);
}
// now put the output into the variables
- if (!this->RunOutputVariable.empty()) {
- this->Makefile->AddDefinition(this->RunOutputVariable,
+ if (arguments.RunOutputVariable) {
+ this->Makefile->AddDefinition(*arguments.RunOutputVariable,
runOutputContents);
}
+ if (arguments.RunOutputStdOutVariable) {
+ this->Makefile->AddDefinition(*arguments.RunOutputStdOutVariable,
+ runOutputStdOutContents);
+ }
+ if (arguments.RunOutputStdErrVariable) {
+ this->Makefile->AddDefinition(*arguments.RunOutputStdErrVariable,
+ runOutputStdErrContents);
+ }
- if (!this->OutputVariable.empty()) {
+ if (arguments.OutputVariable && !arguments.CompileOutputVariable) {
// if the TryCompileCore saved output in this outputVariable then
// prepend that output to this output
cmValue compileOutput =
- this->Makefile->GetDefinition(this->OutputVariable);
+ this->Makefile->GetDefinition(*arguments.OutputVariable);
if (compileOutput) {
runOutputContents = *compileOutput + runOutputContents;
}
- this->Makefile->AddDefinition(this->OutputVariable, runOutputContents);
+ this->Makefile->AddDefinition(*arguments.OutputVariable,
+ runOutputContents);
}
}
}
@@ -179,8 +182,10 @@ bool cmTryRunCommand::InitialPass(std::vector<std::string> const& argv,
return true;
}
-void cmTryRunCommand::RunExecutable(const std::string& runArgs,
- std::string* out)
+void TryRunCommandImpl::RunExecutable(const std::string& runArgs,
+ cm::optional<std::string> const& workDir,
+ std::string* out, std::string* stdOut,
+ std::string* stdErr)
{
int retVal = -1;
@@ -204,9 +209,10 @@ void cmTryRunCommand::RunExecutable(const std::string& runArgs,
finalCommand += runArgs;
}
bool worked = cmSystemTools::RunSingleCommand(
- finalCommand, out, out, &retVal,
- this->WorkingDirectory.empty() ? nullptr : this->WorkingDirectory.c_str(),
- cmSystemTools::OUTPUT_NONE, cmDuration::zero());
+ finalCommand, stdOut || stdErr ? stdOut : out,
+ stdOut || stdErr ? stdErr : out, &retVal,
+ workDir ? workDir->c_str() : nullptr, cmSystemTools::OUTPUT_NONE,
+ cmDuration::zero());
// set the run var
char retChar[16];
const char* retStr;
@@ -225,9 +231,10 @@ void cmTryRunCommand::RunExecutable(const std::string& runArgs,
executable, two cache variables are created which will hold the results
the executable would have produced.
*/
-void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
- const std::string& srcFile,
- std::string* out)
+void TryRunCommandImpl::DoNotRunExecutable(
+ const std::string& runArgs, const std::string& srcFile,
+ std::string const& compileResultVariable, std::string* out,
+ std::string* stdOut, std::string* stdErr)
{
// copy the executable out of the CMakeFiles/ directory, so it is not
// removed at the end of try_run() and the user can run it manually
@@ -246,6 +253,10 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
std::string internalRunOutputName =
this->RunResultVariable + "__TRYRUN_OUTPUT";
+ std::string internalRunOutputStdOutName =
+ this->RunResultVariable + "__TRYRUN_OUTPUT_STDOUT";
+ std::string internalRunOutputStdErrName =
+ this->RunResultVariable + "__TRYRUN_OUTPUT_STDERR";
bool error = false;
if (!this->Makefile->GetDefinition(this->RunResultVariable)) {
@@ -269,7 +280,51 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
}
// is the output from the executable used ?
- if (out) {
+ if (stdOut || stdErr) {
+ if (!this->Makefile->GetDefinition(internalRunOutputStdOutName)) {
+ // if the variables doesn't exist, create it with a helpful error text
+ // and mark it as advanced
+ std::string comment = cmStrCat(
+ "Output of try_run(), contains the text, which the executable "
+ "would have printed on stdout on its target platform.\n",
+ detailsString);
+
+ this->Makefile->AddCacheDefinition(
+ internalRunOutputStdOutName, "PLEASE_FILL_OUT-NOTFOUND",
+ comment.c_str(), cmStateEnums::STRING);
+ cmState* state = this->Makefile->GetState();
+ cmValue existing =
+ state->GetCacheEntryValue(internalRunOutputStdOutName);
+ if (existing) {
+ state->SetCacheEntryProperty(internalRunOutputStdOutName, "ADVANCED",
+ "1");
+ }
+
+ error = true;
+ }
+
+ if (!this->Makefile->GetDefinition(internalRunOutputStdErrName)) {
+ // if the variables doesn't exist, create it with a helpful error text
+ // and mark it as advanced
+ std::string comment = cmStrCat(
+ "Output of try_run(), contains the text, which the executable "
+ "would have printed on stderr on its target platform.\n",
+ detailsString);
+
+ this->Makefile->AddCacheDefinition(
+ internalRunOutputStdErrName, "PLEASE_FILL_OUT-NOTFOUND",
+ comment.c_str(), cmStateEnums::STRING);
+ cmState* state = this->Makefile->GetState();
+ cmValue existing =
+ state->GetCacheEntryValue(internalRunOutputStdErrName);
+ if (existing) {
+ state->SetCacheEntryProperty(internalRunOutputStdErrName, "ADVANCED",
+ "1");
+ }
+
+ error = true;
+ }
+ } else if (out) {
if (!this->Makefile->GetDefinition(internalRunOutputName)) {
// if the variables doesn't exist, create it with a helpful error text
// and mark it as advanced
@@ -317,7 +372,34 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
" to\n"
" the exit code (in many cases 0 for success), otherwise "
"enter \"FAILED_TO_RUN\".\n");
- if (out) {
+ if (stdOut || stdErr) {
+ if (stdOut) {
+ comment += internalRunOutputStdOutName;
+ comment +=
+ "\n contains the text the executable "
+ "would have printed on stdout.\n"
+ " If the executable would not have been able to run, set ";
+ comment += internalRunOutputStdOutName;
+ comment += " empty.\n"
+ " Otherwise check if the output is evaluated by the "
+ "calling CMake code. If so,\n"
+ " check what the source file would have printed when "
+ "called with the given arguments.\n";
+ }
+ if (stdErr) {
+ comment += internalRunOutputStdErrName;
+ comment +=
+ "\n contains the text the executable "
+ "would have printed on stderr.\n"
+ " If the executable would not have been able to run, set ";
+ comment += internalRunOutputStdErrName;
+ comment += " empty.\n"
+ " Otherwise check if the output is evaluated by the "
+ "calling CMake code. If so,\n"
+ " check what the source file would have printed when "
+ "called with the given arguments.\n";
+ }
+ } else if (out) {
comment += internalRunOutputName;
comment +=
"\n contains the text the executable "
@@ -330,8 +412,9 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
" check what the source file would have printed when "
"called with the given arguments.\n";
}
+
comment += "The ";
- comment += this->CompileResultVariable;
+ comment += compileResultVariable;
comment += " variable holds the build result for this try_run().\n\n"
"Source file : ";
comment += srcFile + "\n";
@@ -370,7 +453,37 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
return;
}
- if (out) {
+ if (stdOut || stdErr) {
+ if (stdOut) {
+ (*stdOut) = *this->Makefile->GetDefinition(internalRunOutputStdOutName);
+ }
+ if (stdErr) {
+ (*stdErr) = *this->Makefile->GetDefinition(internalRunOutputStdErrName);
+ }
+ } else if (out) {
(*out) = *this->Makefile->GetDefinition(internalRunOutputName);
}
}
+}
+
+bool cmTryRunCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ cmMakefile& mf = status.GetMakefile();
+
+ if (args.size() < 4) {
+ mf.IssueMessage(MessageType::FATAL_ERROR,
+ "The try_run() command requires at least 4 arguments.");
+ return false;
+ }
+
+ if (mf.GetCMakeInstance()->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
+ mf.IssueMessage(
+ MessageType::FATAL_ERROR,
+ "The try_run() command is not supported in --find-package mode.");
+ return false;
+ }
+
+ TryRunCommandImpl tr(&mf);
+ return tr.TryRunCode(args);
+}
diff --git a/Source/cmTryRunCommand.h b/Source/cmTryRunCommand.h
index d45acd8..38e3638 100644
--- a/Source/cmTryRunCommand.h
+++ b/Source/cmTryRunCommand.h
@@ -7,47 +7,7 @@
#include <string>
#include <vector>
-#include <cm/memory>
-
-#include "cmCommand.h"
-#include "cmCoreTryCompile.h"
-
class cmExecutionStatus;
-/** \class cmTryRunCommand
- * \brief Specifies where to install some files
- *
- * cmTryRunCommand is used to test if source code can be compiled
- */
-class cmTryRunCommand : public cmCoreTryCompile
-{
-public:
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- return cm::make_unique<cmTryRunCommand>();
- }
-
- /**
- * This is called when the command is first encountered in
- * the CMakeLists.txt file.
- */
- bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status) override;
-
-private:
- void RunExecutable(const std::string& runArgs,
- std::string* runOutputContents);
- void DoNotRunExecutable(const std::string& runArgs,
- const std::string& srcFile,
- std::string* runOutputContents);
-
- std::string CompileResultVariable;
- std::string RunResultVariable;
- std::string OutputVariable;
- std::string RunOutputVariable;
- std::string CompileOutputVariable;
- std::string WorkingDirectory;
-};
+bool cmTryRunCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index a7460e8..44c089e 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -50,24 +50,6 @@
#include "cmValue.h"
#include "cmVisualStudioGeneratorOptions.h"
-namespace {
-std::string getProjectFileExtension(VsProjectType projectType)
-{
- switch (projectType) {
- case VsProjectType::csproj:
- return ".csproj";
- case VsProjectType::proj:
- return ".proj";
- case VsProjectType::vcxproj:
- return ".vcxproj";
- // Valid inputs shouldn't reach here. This default is needed so that all
- // paths return value (C4715).
- default:
- return "";
- }
-}
-}
-
struct cmIDEFlagTable;
static void ConvertToWindowsSlash(std::string& s);
@@ -253,6 +235,31 @@ static bool cmVS10IsTargetsFile(std::string const& path)
return cmSystemTools::Strucmp(ext.c_str(), ".targets") == 0;
}
+static VsProjectType computeProjectType(cmGeneratorTarget const* t)
+{
+ if (t->IsCSharpOnly()) {
+ return VsProjectType::csproj;
+ }
+ return VsProjectType::vcxproj;
+}
+
+static std::string computeProjectFileExtension(VsProjectType projectType)
+{
+ switch (projectType) {
+ case VsProjectType::csproj:
+ return ".csproj";
+ case VsProjectType::proj:
+ return ".proj";
+ default:
+ return ".vcxproj";
+ }
+}
+
+static std::string computeProjectFileExtension(cmGeneratorTarget const* t)
+{
+ return computeProjectFileExtension(computeProjectType(t));
+}
+
cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator(
cmGeneratorTarget* target, cmGlobalVisualStudio10Generator* gg)
: GeneratorTarget(target)
@@ -359,10 +366,10 @@ void cmVisualStudio10TargetGenerator::Generate()
"by the generator"));
}
- this->ProjectType = this->ComputeProjectType(this->GeneratorTarget);
+ this->ProjectType = computeProjectType(this->GeneratorTarget);
this->Managed = this->ProjectType == VsProjectType::csproj;
const std::string ProjectFileExtension =
- getProjectFileExtension(this->ProjectType);
+ computeProjectFileExtension(this->ProjectType);
if (this->ProjectType == VsProjectType::csproj &&
this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
@@ -423,12 +430,10 @@ void cmVisualStudio10TargetGenerator::Generate()
char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
BuildFileStream.write(magic, 3);
- if (this->ProjectType == VsProjectType::proj) {
- this->WriteZeroCheckProj(BuildFileStream);
- } else if (this->ProjectType == VsProjectType::csproj &&
- this->GeneratorTarget->IsDotNetSdkTarget() &&
- this->GlobalGenerator->GetVersion() >=
- cmGlobalVisualStudioGenerator::VSVersion::VS16) {
+ if (this->ProjectType == VsProjectType::csproj &&
+ this->GeneratorTarget->IsDotNetSdkTarget() &&
+ this->GlobalGenerator->GetVersion() >=
+ cmGlobalVisualStudioGenerator::VSVersion::VS16) {
this->WriteSdkStyleProjectFile(BuildFileStream);
} else {
this->WriteClassicMsBuildProjectFile(BuildFileStream);
@@ -490,7 +495,7 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
e1.Element("PreferredToolArchitecture", hostArch);
}
- // ALL_BUILD and ZERO_CHECK projects transitively include
+ // The ALL_BUILD, PACKAGE, and ZERO_CHECK projects transitively include
// Microsoft.Common.CurrentVersion.targets which triggers Target
// ResolveNugetPackageAssets when SDK-style targets are in the project.
// However, these projects have no nuget packages to reference and the
@@ -498,7 +503,7 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
// Setting ResolveNugetPackages to false skips this target and the build
// succeeds.
cm::string_view targetName{ this->GeneratorTarget->GetName() };
- if (targetName == "ALL_BUILD" ||
+ if (targetName == "ALL_BUILD" || targetName == "PACKAGE" ||
targetName == CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
Elem e1(e0, "PropertyGroup");
e1.Element("ResolveNugetPackages", "false");
@@ -898,6 +903,7 @@ void cmVisualStudio10TargetGenerator::WriteSdkStyleProjectFile(
// of the IDE.
e1.Element("VCProjectUpgraderObjectName", "NoUpgrade");
e1.Element("ManagedAssembly", "true");
+ e1.Element("AppendTargetFrameworkToOutputPath", "false");
cmValue targetFramework =
this->GeneratorTarget->GetProperty("DOTNET_TARGET_FRAMEWORK");
@@ -977,45 +983,6 @@ void cmVisualStudio10TargetGenerator::WriteSdkStyleProjectFile(
this->WriteProjectReferences(e0);
}
-void cmVisualStudio10TargetGenerator::WriteZeroCheckProj(
- cmGeneratedFileStream& BuildFileStream)
-{
- // ZERO_CHECK.proj is an XML file without any imports or targets. This is a
- // ProjectReference for other targets and therefore, it needs to follow the
- // ProjectReference protocol as documented here:
- // https://github.com/dotnet/msbuild/blob/main/documentation/ProjectReference-Protocol.md
- //
- // We implement MSBuild target Build from WriteCustomCommand which calls
- // WriteZeroCheckBuildTarget after setting up the command generator. MSBuild
- // target Clean is a no-op as we do all the work for ZERO_CHECK on Build.
- // MSBuild target GetTargetPath is needed and is no-op.
- // MSBuild targets GetNativeManifest and GetCopyToOutputDirectoryItems are
- // needed for MSBuild versions below 15.7 and are no-op. MSBuild target
- // BeforeBuild is needed for supporting GLOBs.
- BuildFileStream << "<?xml version=\"1.0\" encoding=\""
- << this->GlobalGenerator->Encoding() << "\"?>";
- {
- Elem e0(BuildFileStream, "Project");
- e0.Attribute("DefaultTargets", "Build");
- e0.Attribute("ToolsVersion", this->GlobalGenerator->GetToolsVersion());
- e0.Attribute("xmlns",
- "http://schemas.microsoft.com/developer/msbuild/2003");
-
- this->WriteCustomCommands(e0);
-
- for (const char* targetName :
- { "Clean", "GetTargetPath", "GetNativeManifest",
- "GetCopyToOutputDirectoryItems" }) {
- {
- Elem e1(e0, "Target");
- e1.Attribute("Name", targetName);
- }
- }
-
- this->WriteZeroCheckBeforeBuildTarget(e0);
- }
-}
-
void cmVisualStudio10TargetGenerator::WriteCommonPropertyGroupGlobals(Elem& e1)
{
e1.Attribute("Label", "Globals");
@@ -1557,6 +1524,10 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues(
this->ASanEnabledConfigurations.end()) {
e1.Element("EnableAsan", "true");
}
+ if (this->FuzzerEnabledConfigurations.find(config) !=
+ this->FuzzerEnabledConfigurations.end()) {
+ e1.Element("EnableFuzzer", "true");
+ }
{
auto s = this->SpectreMitigation.find(config);
if (s != this->SpectreMitigation.end()) {
@@ -1735,16 +1706,11 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule(
}
}
}
- if (this->ProjectType == VsProjectType::proj) {
- this->WriteZeroCheckBuildTarget(e0, command, source);
- return;
- }
-
cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
std::unique_ptr<Elem> spe1;
std::unique_ptr<Elem> spe2;
- if (this->ProjectType == VsProjectType::vcxproj) {
+ if (this->ProjectType != VsProjectType::csproj) {
spe1 = cm::make_unique<Elem>(e0, "ItemGroup");
spe2 = cm::make_unique<Elem>(*spe1, "CustomBuild");
this->WriteSource(*spe2, source);
@@ -1942,7 +1908,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
// Write out group file
std::string path = cmStrCat(
this->LocalGenerator->GetCurrentBinaryDirectory(), '/', this->Name,
- this->ComputeProjectFileExtension(this->GeneratorTarget), ".filters");
+ computeProjectFileExtension(this->GeneratorTarget), ".filters");
cmGeneratedFileStream fout(path);
fout.SetCopyIfDifferent(true);
char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
@@ -2930,7 +2896,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions(
Elem& e0)
{
cmStateEnums::TargetType ttype = this->GeneratorTarget->GetType();
- if (ttype > cmStateEnums::GLOBAL_TARGET) {
+ if (ttype > cmStateEnums::INTERFACE_LIBRARY) {
return;
}
if (this->ProjectType == VsProjectType::csproj) {
@@ -3097,134 +3063,6 @@ void cmVisualStudio10TargetGenerator::OutputLinkIncremental(
}
}
-void cmVisualStudio10TargetGenerator::WriteZeroCheckBuildTarget(
- cmVisualStudio10TargetGenerator::Elem& e0, const cmCustomCommand& command,
- const cmSourceFile* source)
-{
- cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
-
- Elem e1(e0, "Target");
- e1.Attribute("Name", "Build");
-
- std::string noConfig{};
- cmCustomCommandGenerator ccg{ command, noConfig, lg, true };
- std::string comment = lg->ConstructComment(ccg);
- comment = cmVS10EscapeComment(comment);
- std::string script = lg->ConstructScript(ccg);
- bool symbolic = false;
- // input files for custom command
- std::stringstream additional_inputs;
- {
- const char* sep = "";
- if (this->ProjectType == VsProjectType::proj) {
- // List explicitly the path to primary input.
- std::string sourceFullPath = source->GetFullPath();
- ConvertToWindowsSlash(sourceFullPath);
- additional_inputs << sourceFullPath;
- sep = ";";
- }
-
- // Avoid listing an input more than once.
- std::set<std::string> unique_inputs;
- // The source is either implicitly an input or has been added above.
- unique_inputs.insert(source->GetFullPath());
-
- for (std::string const& d : ccg.GetDepends()) {
- std::string dep;
- if (lg->GetRealDependency(d, noConfig, dep)) {
- if (!unique_inputs.insert(dep).second) {
- // already listed
- continue;
- }
- ConvertToWindowsSlash(dep);
- additional_inputs << sep << dep;
- sep = ";";
- if (!symbolic) {
- if (cmSourceFile* sf = this->Makefile->GetSource(
- dep, cmSourceFileLocationKind::Known)) {
- symbolic = sf->GetPropertyAsBool("SYMBOLIC");
- }
- }
- }
- }
- }
- // output files for custom command
- std::stringstream outputs;
- {
- const char* sep = "";
- for (std::string const& o : ccg.GetOutputs()) {
- std::string out = o;
- ConvertToWindowsSlash(out);
- outputs << sep << out;
- sep = ";";
- if (!symbolic) {
- if (cmSourceFile* sf =
- this->Makefile->GetSource(o, cmSourceFileLocationKind::Known)) {
- symbolic = sf->GetPropertyAsBool("SYMBOLIC");
- }
- }
- }
- }
- script += lg->FinishConstructScript(this->ProjectType);
-
- e1.Attribute("Inputs", cmVS10EscapeAttr(additional_inputs.str()));
- e1.Attribute("Outputs", cmVS10EscapeAttr(outputs.str()));
-
- e1.SetHasElements();
-
- if (!comment.empty()) {
- Elem(e1, "Message").Attribute("Text", comment);
- }
- Elem(e1, "Exec").Attribute("Command", script);
-}
-
-void cmVisualStudio10TargetGenerator::WriteZeroCheckBeforeBuildTarget(
- cmVisualStudio10TargetGenerator::Elem& e0)
-{
- const auto& commands = this->GeneratorTarget->GetPreBuildCommands();
- if (commands.empty()) {
- return;
- }
-
- {
- Elem e1(e0, "Target");
- e1.Attribute("Name", "BeforeBuild");
- e1.Attribute("BeforeTargets", "Build");
-
- cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
- std::string script;
- const char* pre = "";
- std::string comment;
- for (cmCustomCommand const& cc : commands) {
- cmCustomCommandGenerator ccg(cc, std::string{}, lg);
- if (!ccg.HasOnlyEmptyCommandLines()) {
- comment += pre;
- comment += lg->ConstructComment(ccg);
- script += pre;
- pre = "\n";
- script += lg->ConstructScript(ccg);
- }
- }
-
- if (script.empty()) {
- return;
- }
-
- script += lg->FinishConstructScript(this->ProjectType);
- comment = cmVS10EscapeComment(comment);
- std::string strippedComment = comment;
- strippedComment.erase(
- std::remove(strippedComment.begin(), strippedComment.end(), '\t'),
- strippedComment.end());
-
- e1.SetHasElements();
- if (!comment.empty() && !strippedComment.empty()) {
- Elem(e1, "Message").Attribute("Text", comment);
- }
- Elem(e1, "Exec").Attribute("Command", script);
- }
-}
-
std::vector<std::string> cmVisualStudio10TargetGenerator::GetIncludes(
std::string const& config, std::string const& lang) const
{
@@ -3300,6 +3138,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
this->LangForClCompile = langForClCompile;
if (!langForClCompile.empty()) {
this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+ cmBuildStep::Compile,
langForClCompile, configName);
this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
langForClCompile, configName);
@@ -3311,10 +3150,17 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
}
// Check if ASan is enabled.
- if (flags.find("/fsanitize=address") != std::string::npos) {
+ if (flags.find("/fsanitize=address") != std::string::npos ||
+ flags.find("-fsanitize=address") != std::string::npos) {
this->ASanEnabledConfigurations.insert(configName);
}
+ // Check if (lib)Fuzzer is enabled.
+ if (flags.find("/fsanitize=fuzzer") != std::string::npos ||
+ flags.find("-fsanitize=fuzzer") != std::string::npos) {
+ this->FuzzerEnabledConfigurations.insert(configName);
+ }
+
// Precompile Headers
std::string pchHeader =
this->GeneratorTarget->GetPchHeader(configName, linkLanguage);
@@ -3356,7 +3202,9 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
// anymore, because cmGeneratorTarget may not be aware that the
// target uses C++/CLI.
if (flags.find("/clr") != std::string::npos ||
- defineFlags.find("/clr") != std::string::npos) {
+ flags.find("-clr") != std::string::npos ||
+ defineFlags.find("/clr") != std::string::npos ||
+ defineFlags.find("-clr") != std::string::npos) {
if (configName == this->Configurations[0]) {
std::string message = "For the target \"" +
this->GeneratorTarget->GetName() +
@@ -3675,8 +3523,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
// Get compile flags for CUDA in this directory.
std::string flags;
- this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, "CUDA",
- configName);
+ this->LocalGenerator->AddLanguageFlags(
+ flags, this->GeneratorTarget, cmBuildStep::Compile, "CUDA", configName);
this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, "CUDA",
configName);
@@ -3947,7 +3795,8 @@ bool cmVisualStudio10TargetGenerator::ComputeMasmOptions(
std::string flags;
this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
- "ASM_MASM", configName);
+ cmBuildStep::Compile, "ASM_MASM",
+ configName);
masmOptions.Parse(flags);
@@ -3999,7 +3848,8 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions(
std::string flags;
this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
- "ASM_NASM", configName);
+ cmBuildStep::Compile, "ASM_NASM",
+ configName);
flags += " -f";
flags += this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_OBJECT_FORMAT");
nasmOptions.Parse(flags);
@@ -4743,7 +4593,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences(Elem& e0)
path = *p;
} else {
path = cmStrCat(lg->GetCurrentBinaryDirectory(), '/', dt->GetName(),
- this->ComputeProjectFileExtension(dt));
+ computeProjectFileExtension(dt));
}
ConvertToWindowsSlash(path);
Elem e2(e1, "ProjectReference");
@@ -5597,26 +5447,6 @@ std::string cmVisualStudio10TargetGenerator::GetCMakeFilePath(
return path;
}
-std::string cmVisualStudio10TargetGenerator::ComputeProjectFileExtension(
- cmGeneratorTarget const* t) const
-{
- return getProjectFileExtension(this->ComputeProjectType(t));
-}
-
-VsProjectType cmVisualStudio10TargetGenerator::ComputeProjectType(
- cmGeneratorTarget const* t) const
-{
- if (this->GlobalGenerator->GetVersion() >=
- cmGlobalVisualStudioGenerator::VSVersion::VS16 &&
- t->GetName() == CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
- return VsProjectType::proj;
- }
- if (t->IsCSharpOnly()) {
- return VsProjectType::csproj;
- }
- return VsProjectType::vcxproj;
-}
-
void cmVisualStudio10TargetGenerator::WriteStdOutEncodingUtf8(Elem& e1)
{
if (this->GlobalGenerator->IsUtf8EncodingSupported()) {
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 7a0b8da..17dcecd 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -231,6 +231,7 @@ private:
bool TargetCompileAsWinRT;
std::set<std::string> IPOEnabledConfigurations;
std::set<std::string> ASanEnabledConfigurations;
+ std::set<std::string> FuzzerEnabledConfigurations;
std::map<std::string, std::string> SpectreMitigation;
cmGlobalVisualStudio10Generator* const GlobalGenerator;
cmLocalVisualStudio10Generator* const LocalGenerator;
@@ -264,13 +265,6 @@ private:
void WriteClassicMsBuildProjectFile(cmGeneratedFileStream& BuildFileStream);
void WriteSdkStyleProjectFile(cmGeneratedFileStream& BuildFileStream);
- void WriteZeroCheckProj(cmGeneratedFileStream& BuildFileStream);
- void WriteZeroCheckBuildTarget(cmVisualStudio10TargetGenerator::Elem& e0,
- const cmCustomCommand& command,
- const cmSourceFile* source);
- void WriteZeroCheckBeforeBuildTarget(
- cmVisualStudio10TargetGenerator::Elem& e0);
-
void WriteCommonPropertyGroupGlobals(
cmVisualStudio10TargetGenerator::Elem& e1);
@@ -282,7 +276,4 @@ private:
void ParseSettingsProperty(const std::string& settingsPropertyValue,
ConfigToSettings& toolSettings);
std::string GetCMakeFilePath(const char* name) const;
-
- std::string ComputeProjectFileExtension(cmGeneratorTarget const* t) const;
- VsProjectType ComputeProjectType(cmGeneratorTarget const* t) const;
};
diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx
index fb94273..e80d1fc 100644
--- a/Source/cmWhileCommand.cxx
+++ b/Source/cmWhileCommand.cxx
@@ -96,7 +96,7 @@ bool cmWhileFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
cmExecutionStatus status(mf);
mf.ExecuteCommand(fn, status);
if (status.GetReturnInvoked()) {
- inStatus.SetReturnInvoked();
+ inStatus.SetReturnInvoked(status.GetReturnVariables());
return true;
}
if (status.GetBreakInvoked()) {
diff --git a/Source/cmWindowsRegistry.h b/Source/cmWindowsRegistry.h
index 2eed297..f4a0e7b 100644
--- a/Source/cmWindowsRegistry.h
+++ b/Source/cmWindowsRegistry.h
@@ -2,6 +2,8 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
+#include "cmConfigure.h" // IWYU pragma: keep
+
#include <cstdint> // IWYU pragma: keep
#include <string>
#include <vector>
diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx
index a62015f..e727d22 100644
--- a/Source/cmXCodeScheme.cxx
+++ b/Source/cmXCodeScheme.cxx
@@ -67,9 +67,14 @@ void cmXCodeScheme::WriteXCodeXCScheme(std::ostream& fout,
xout.Attribute("LastUpgradeVersion", WriteVersionString());
xout.Attribute("version", "1.3");
+ cmValue propDftCfg =
+ Target->GetTarget()->GetProperty("XCODE_SCHEME_LAUNCH_CONFIGURATION");
+ std::string launchConfiguration =
+ !propDftCfg.IsEmpty() ? *propDftCfg : "Debug";
+
WriteBuildAction(xout, container);
WriteTestAction(xout, FindConfiguration("Debug"), container);
- WriteLaunchAction(xout, FindConfiguration("Debug"), container);
+ WriteLaunchAction(xout, FindConfiguration(launchConfiguration), container);
WriteProfileAction(xout, FindConfiguration("Release"));
WriteAnalyzeAction(xout, FindConfiguration("Debug"));
WriteArchiveAction(xout, FindConfiguration("Release"));
@@ -198,6 +203,23 @@ void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout,
WriteLaunchActionAttribute(xout, "enableUBSanitizer",
"XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER");
+
+ if (cmValue value = this->Target->GetTarget()->GetProperty(
+ "XCODE_SCHEME_ENABLE_GPU_API_VALIDATION")) {
+ if (value.IsOff()) {
+ xout.Attribute("enableGPUValidationMode",
+ "1"); // unset means YES, "1" means NO
+ }
+ }
+
+ if (cmValue value = this->Target->GetTarget()->GetProperty(
+ "XCODE_SCHEME_ENABLE_GPU_SHADER_VALIDATION")) {
+ if (value.IsOn()) {
+ xout.Attribute("enableGPUShaderValidationMode",
+ "2"); // unset means NO, "2" means YES
+ }
+ }
+
WriteLaunchActionAttribute(
xout, "stopOnEveryUBSanitizerIssue",
"XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP");
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index e6fa219..3b105e3 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -3,6 +3,7 @@
#include "cmake.h"
#include <algorithm>
+#include <array>
#include <cstdio>
#include <cstdlib>
#include <cstring>
@@ -62,6 +63,7 @@
#if !defined(CMAKE_BOOTSTRAP)
# include <unordered_map>
+# include <cm3p/curl/curl.h>
# include <cm3p/json/writer.h>
# include "cmFileAPI.h"
@@ -251,6 +253,8 @@ Json::Value cmake::ReportCapabilitiesJson() const
std::vector<cmake::GeneratorInfo> generatorInfoList;
this->GetRegisteredGenerators(generatorInfoList);
+ auto* curlVersion = curl_version_info(CURLVERSION_FIRST);
+
JsonValueMapType generatorMap;
for (cmake::GeneratorInfo const& gi : generatorInfoList) {
if (gi.isAlias) { // skip aliases, they are there for compatibility reasons
@@ -285,6 +289,7 @@ Json::Value cmake::ReportCapabilitiesJson() const
obj["generators"] = generators;
obj["fileApi"] = cmFileAPI::ReportCapabilities();
obj["serverMode"] = false;
+ obj["tls"] = static_cast<bool>(curlVersion->features & CURL_VERSION_SSL);
return obj;
}
@@ -405,9 +410,6 @@ void cmake::PrintPresetEnvironment()
// Parse the args
bool cmake::SetCacheArgs(const std::vector<std::string>& args)
{
- auto findPackageMode = false;
- auto seenScriptOption = false;
-
auto DefineLambda = [](std::string const& entry, cmake* state) -> bool {
std::string var;
std::string value;
@@ -498,10 +500,10 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
GetProjectCommandsInScriptMode(state->GetState());
// Documented behavior of CMAKE{,_CURRENT}_{SOURCE,BINARY}_DIR is to be
// set to $PWD for -P mode.
+ state->SetWorkingMode(SCRIPT_MODE);
state->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
state->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
state->ReadListFile(args, path);
- seenScriptOption = true;
return true;
};
@@ -565,12 +567,12 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
"No install directory specified for --install-prefix",
CommandArgument::Values::One, PrefixLambda },
CommandArgument{ "--find-package", CommandArgument::Values::Zero,
- CommandArgument::setToTrue(findPackageMode) },
+ IgnoreAndTrueLambda },
};
for (decltype(args.size()) i = 1; i < args.size(); ++i) {
std::string const& arg = args[i];
- if (arg == "--" && seenScriptOption) {
+ if (arg == "--" && this->GetWorkingMode() == SCRIPT_MODE) {
// Stop processing CMake args and avoid possible errors
// when arbitrary args are given to CMake script.
break;
@@ -585,7 +587,7 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
}
}
- if (findPackageMode) {
+ if (this->GetWorkingMode() == FIND_PACKAGE_MODE) {
return this->FindPackage(args);
}
@@ -780,6 +782,7 @@ enum class ListPresets
Configure,
Build,
Test,
+ Package,
All,
};
}
@@ -790,7 +793,6 @@ void cmake::SetArgs(const std::vector<std::string>& args)
bool haveToolset = false;
bool havePlatform = false;
bool haveBArg = false;
- bool scriptMode = false;
std::string possibleUnknownArg;
std::string extraProvidedPath;
#if !defined(CMAKE_BOOTSTRAP)
@@ -873,7 +875,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
CommandArgument{ "-P", "-P must be followed by a file name.",
CommandArgument::Values::One,
CommandArgument::RequiresSeparator::No,
- CommandArgument::setToTrue(scriptMode) },
+ IgnoreAndTrueLambda },
CommandArgument{ "-D", "-D must be followed with VAR=VALUE.",
CommandArgument::Values::One,
CommandArgument::RequiresSeparator::No,
@@ -955,7 +957,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
CommandArgument::Values::One,
[](std::string const& value, cmake* state) -> bool {
const auto logLevel = StringToLogLevel(value);
- if (logLevel == LogLevel::LOG_UNDEFINED) {
+ if (logLevel == Message::LogLevel::LOG_UNDEFINED) {
cmSystemTools::Error(
"Invalid level specified for --log-level");
return false;
@@ -971,7 +973,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
CommandArgument::Values::One,
[](std::string const& value, cmake* state) -> bool {
const auto logLevel = StringToLogLevel(value);
- if (logLevel == LogLevel::LOG_UNDEFINED) {
+ if (logLevel == Message::LogLevel::LOG_UNDEFINED) {
cmSystemTools::Error(
"Invalid level specified for --loglevel");
return false;
@@ -1136,12 +1138,14 @@ void cmake::SetArgs(const std::vector<std::string>& args)
listPresets = ListPresets::Build;
} else if (value == "test") {
listPresets = ListPresets::Test;
+ } else if (value == "package") {
+ listPresets = ListPresets::Package;
} else if (value == "all") {
listPresets = ListPresets::All;
} else {
cmSystemTools::Error(
"Invalid value specified for --list-presets.\n"
- "Valid values are configure, build, test, or all. "
+ "Valid values are configure, build, test, package, or all. "
"When no value is passed the default is configure.");
return false;
}
@@ -1165,7 +1169,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
// iterate each argument
std::string const& arg = args[i];
- if (scriptMode && arg == "--") {
+ if (this->GetWorkingMode() == SCRIPT_MODE && arg == "--") {
// Stop processing CMake args and avoid possible errors
// when arbitrary args are given to CMake script.
break;
@@ -1211,12 +1215,12 @@ void cmake::SetArgs(const std::vector<std::string>& args)
}
}
- if (!extraProvidedPath.empty() && !scriptMode) {
+ if (!extraProvidedPath.empty() && this->GetWorkingMode() == NORMAL_MODE) {
this->IssueMessage(MessageType::WARNING,
cmStrCat("Ignoring extra path from command line:\n \"",
extraProvidedPath, "\""));
}
- if (!possibleUnknownArg.empty() && !scriptMode) {
+ if (!possibleUnknownArg.empty() && this->GetWorkingMode() != SCRIPT_MODE) {
cmSystemTools::Error(cmStrCat("Unknown argument ", possibleUnknownArg));
cmSystemTools::Error("Run 'cmake --help' for all supported options.");
exit(1);
@@ -1286,9 +1290,13 @@ void cmake::SetArgs(const std::vector<std::string>& args)
cmCMakePresetsGraph presetsGraph;
auto result = presetsGraph.ReadProjectPresets(this->GetHomeDirectory());
if (result != cmCMakePresetsGraph::ReadFileResult::READ_OK) {
- cmSystemTools::Error(
+ std::string errorMsg =
cmStrCat("Could not read presets from ", this->GetHomeDirectory(),
- ": ", cmCMakePresetsGraph::ResultToString(result)));
+ ": ", cmCMakePresetsGraph::ResultToString(result));
+ if (!presetsGraph.errors.empty()) {
+ errorMsg = cmStrCat(errorMsg, "\nErrors:\n", presetsGraph.errors);
+ }
+ cmSystemTools::Error(errorMsg);
return;
}
@@ -1299,6 +1307,8 @@ void cmake::SetArgs(const std::vector<std::string>& args)
presetsGraph.PrintBuildPresetList();
} else if (listPresets == ListPresets::Test) {
presetsGraph.PrintTestPresetList();
+ } else if (listPresets == ListPresets::Package) {
+ presetsGraph.PrintPackagePresetList();
} else if (listPresets == ListPresets::All) {
presetsGraph.PrintAllPresets();
}
@@ -1402,23 +1412,52 @@ void cmake::SetArgs(const std::vector<std::string>& args)
#endif
}
-cmake::LogLevel cmake::StringToLogLevel(const std::string& levelStr)
-{
- using LevelsPair = std::pair<std::string, LogLevel>;
- static const std::vector<LevelsPair> levels = {
- { "error", LogLevel::LOG_ERROR }, { "warning", LogLevel::LOG_WARNING },
- { "notice", LogLevel::LOG_NOTICE }, { "status", LogLevel::LOG_STATUS },
- { "verbose", LogLevel::LOG_VERBOSE }, { "debug", LogLevel::LOG_DEBUG },
- { "trace", LogLevel::LOG_TRACE }
+namespace {
+using LevelsPair = std::pair<cm::string_view, Message::LogLevel>;
+using LevelsPairArray = std::array<LevelsPair, 7>;
+const LevelsPairArray& getStringToLogLevelPairs()
+{
+ static const LevelsPairArray levels = {
+ { { "error", Message::LogLevel::LOG_ERROR },
+ { "warning", Message::LogLevel::LOG_WARNING },
+ { "notice", Message::LogLevel::LOG_NOTICE },
+ { "status", Message::LogLevel::LOG_STATUS },
+ { "verbose", Message::LogLevel::LOG_VERBOSE },
+ { "debug", Message::LogLevel::LOG_DEBUG },
+ { "trace", Message::LogLevel::LOG_TRACE } }
};
+ return levels;
+}
+} // namespace
- const auto levelStrLowCase = cmSystemTools::LowerCase(levelStr);
+Message::LogLevel cmake::StringToLogLevel(cm::string_view levelStr)
+{
+ const LevelsPairArray& levels = getStringToLogLevelPairs();
+ const auto levelStrLowCase =
+ cmSystemTools::LowerCase(std::string{ levelStr });
+
+ // NOLINTNEXTLINE(readability-qualified-auto)
const auto it = std::find_if(levels.cbegin(), levels.cend(),
[&levelStrLowCase](const LevelsPair& p) {
return p.first == levelStrLowCase;
});
- return (it != levels.cend()) ? it->second : LogLevel::LOG_UNDEFINED;
+ return (it != levels.cend()) ? it->second : Message::LogLevel::LOG_UNDEFINED;
+}
+
+std::string cmake::LogLevelToString(Message::LogLevel level)
+{
+ const LevelsPairArray& levels = getStringToLogLevelPairs();
+
+ // NOLINTNEXTLINE(readability-qualified-auto)
+ const auto it =
+ std::find_if(levels.cbegin(), levels.cend(),
+ [&level](const LevelsPair& p) { return p.second == level; });
+ const cm::string_view levelStrLowerCase =
+ (it != levels.cend()) ? it->first : "undefined";
+ std::string levelStrUpperCase =
+ cmSystemTools::UpperCase(std::string{ levelStrLowerCase });
+ return levelStrUpperCase;
}
cmake::TraceFormat cmake::StringToTraceFormat(const std::string& traceStr)
@@ -1800,7 +1839,8 @@ void cmake::SetHomeDirectoryViaCommandLine(std::string const& path)
}
auto prev_path = this->GetHomeDirectory();
- if (prev_path != path && !prev_path.empty()) {
+ if (prev_path != path && !prev_path.empty() &&
+ this->GetWorkingMode() == NORMAL_MODE) {
this->IssueMessage(MessageType::WARNING,
cmStrCat("Ignoring extra path from command line:\n \"",
prev_path, "\""));
@@ -2099,6 +2139,9 @@ int cmake::ActualConfigure()
this->UpdateConversionPathTable();
this->CleanupCommandsAndMacros();
+ cmSystemTools::RemoveADirectory(this->GetHomeOutputDirectory() +
+ "/CMakeFiles/CMakeScratch");
+
int res = this->DoPreConfigureChecks();
if (res < 0) {
return -2;
diff --git a/Source/cmake.h b/Source/cmake.h
index 3c6af17..8c0fece 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -119,19 +119,6 @@ public:
FIND_PACKAGE_MODE
};
- /** \brief Define log level constants. */
- enum LogLevel
- {
- LOG_UNDEFINED,
- LOG_ERROR,
- LOG_WARNING,
- LOG_NOTICE,
- LOG_STATUS,
- LOG_VERBOSE,
- LOG_DEBUG,
- LOG_TRACE
- };
-
/** \brief Define supported trace formats **/
enum TraceFormat
{
@@ -469,9 +456,10 @@ public:
bool WasLogLevelSetViaCLI() const { return this->LogLevelWasSetViaCLI; }
//! Get the selected log level for `message()` commands during the cmake run.
- LogLevel GetLogLevel() const { return this->MessageLogLevel; }
- void SetLogLevel(LogLevel level) { this->MessageLogLevel = level; }
- static LogLevel StringToLogLevel(const std::string& levelStr);
+ Message::LogLevel GetLogLevel() const { return this->MessageLogLevel; }
+ void SetLogLevel(Message::LogLevel level) { this->MessageLogLevel = level; }
+ static Message::LogLevel StringToLogLevel(cm::string_view levelStr);
+ static std::string LogLevelToString(Message::LogLevel level);
static TraceFormat StringToTraceFormat(const std::string& levelStr);
bool HasCheckInProgress() const
@@ -732,7 +720,7 @@ private:
std::set<std::string> DebugFindPkgs;
std::set<std::string> DebugFindVars;
- LogLevel MessageLogLevel = LogLevel::LOG_STATUS;
+ Message::LogLevel MessageLogLevel = Message::LogLevel::LOG_STATUS;
bool LogLevelWasSetViaCLI = false;
bool LogContext = false;
@@ -873,6 +861,7 @@ private:
F(cxx_std_17) \
F(cxx_std_20) \
F(cxx_std_23) \
+ F(cxx_std_26) \
FOR_EACH_CXX98_FEATURE(F) \
FOR_EACH_CXX11_FEATURE(F) \
FOR_EACH_CXX14_FEATURE(F)
@@ -883,7 +872,8 @@ private:
F(cuda_std_14) \
F(cuda_std_17) \
F(cuda_std_20) \
- F(cuda_std_23)
+ F(cuda_std_23) \
+ F(cuda_std_26)
#define FOR_EACH_HIP_FEATURE(F) \
F(hip_std_98) \
@@ -891,4 +881,5 @@ private:
F(hip_std_14) \
F(hip_std_17) \
F(hip_std_20) \
- F(hip_std_23)
+ F(hip_std_23) \
+ F(hip_std_26)
diff --git a/Source/cmake.version.manifest b/Source/cmake.version.manifest
index e7010c9..79e3d19 100644
--- a/Source/cmake.version.manifest
+++ b/Source/cmake.version.manifest
@@ -1,6 +1,6 @@
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0"
- xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
+ xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows Vista -->
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index 97c275e..6f3d0eb 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -71,7 +71,7 @@ const char* cmDocumentationUsageNote[][2] = {
const char* cmDocumentationOptions[][2] = {
CMAKE_STANDARD_OPTIONS_TABLE,
{ "--preset <preset>,--preset=<preset>", "Specify a configure preset." },
- { "--list-presets", "List available presets." },
+ { "--list-presets[=<type>]", "List available presets." },
{ "-E", "CMake command mode." },
{ "-L[A][H]", "List non-advanced cached variables." },
{ "--fresh",
@@ -82,9 +82,9 @@ const char* cmDocumentationOptions[][2] = {
{ "-N", "View mode only." },
{ "-P <file>", "Process script mode." },
{ "--find-package", "Legacy pkg-config like mode. Do not use." },
- { "--graphviz=[file]",
- "Generate graphviz of dependencies, see "
- "CMakeGraphVizOptions.cmake for more." },
+ { "--graphviz=<file>",
+ "Generate graphviz of dependencies, see CMakeGraphVizOptions.cmake for "
+ "more." },
{ "--system-information [file]", "Dump information about this system." },
{ "--log-level=<ERROR|WARNING|NOTICE|STATUS|VERBOSE|DEBUG|TRACE>",
"Set the verbosity of messages from CMake files. "
@@ -109,8 +109,7 @@ const char* cmDocumentationOptions[][2] = {
{ "--warn-uninitialized", "Warn about uninitialized values." },
{ "--no-warn-unused-cli", "Don't warn about command line options." },
{ "--check-system-vars",
- "Find problems with variable usage in system "
- "files." },
+ "Find problems with variable usage in system files." },
{ "--compile-no-warning-as-error",
"Ignore COMPILE_WARNING_AS_ERROR property and "
"CMAKE_COMPILE_WARNING_AS_ERROR variable." },
@@ -207,7 +206,7 @@ int do_cmake(int ac, char const* const* av)
#ifndef CMAKE_BOOTSTRAP
cmDocumentation doc;
doc.addCMakeStandardDocSections();
- if (doc.CheckOptions(ac, av)) {
+ if (doc.CheckOptions(ac, av, "--")) {
// Construct and print requested documentation.
cmake hcm(cmake::RoleInternal, cmState::Unknown);
hcm.SetHomeDirectory("");
@@ -616,7 +615,7 @@ int do_build(int ac, char const* const* av)
" <dir> = Project binary directory to be built.\n"
" --preset <preset>, --preset=<preset>\n"
" = Specify a build preset.\n"
- " --list-presets\n"
+ " --list-presets[=<type>]\n"
" = List available build presets.\n"
" --parallel [<jobs>], -j [<jobs>]\n"
" = Build in parallel using the given number of jobs. \n"
@@ -627,14 +626,14 @@ int do_build(int ac, char const* const* av)
" specifies a default parallel level when this "
"option\n"
" is not given.\n"
- " --target <tgt>..., -t <tgt>... \n"
+ " -t <tgt>..., --target <tgt>...\n"
" = Build <tgt> instead of default targets.\n"
" --config <cfg> = For multi-configuration tools, choose <cfg>.\n"
" --clean-first = Build target 'clean' first, then build.\n"
" (To clean only, use --target 'clean'.)\n"
" --resolve-package-references={on|only|off}\n"
" = Restore/resolve package references during build.\n"
- " --verbose, -v = Enable verbose output - if supported - including\n"
+ " -v, --verbose = Enable verbose output - if supported - including\n"
" the build commands to be executed. \n"
" -- = Pass remaining options to the native tool.\n"
;
diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx
index 8921aa0..69eb19e 100644
--- a/Source/cmcldeps.cxx
+++ b/Source/cmcldeps.cxx
@@ -273,6 +273,7 @@ int main()
std::string clrest = rest;
// rc: /fo x.dir\x.rc.res -> cl: /out:x.dir\x.rc.res.dep.obj
clrest = replace(clrest, "/fo ", "/out:");
+ clrest = replace(clrest, "-fo ", "-out:");
clrest = replace(clrest, objfile, objfile + ".dep.obj ");
cl = "\"" + cl + "\" /P /DRC_INVOKED /TC ";
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 9ab39f1..00c9bda 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -791,6 +791,10 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
}
if (args[1] == "env") {
+#ifndef CMAKE_BOOTSTRAP
+ cmSystemTools::EnvDiff env;
+#endif
+
auto ai = args.cbegin() + 2;
auto ae = args.cend();
for (; ai != ae; ++ai) {
@@ -803,16 +807,40 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
}
if (cmHasLiteralPrefix(a, "--unset=")) {
// Unset environment variable.
+#ifdef CMAKE_BOOTSTRAP
cmSystemTools::UnPutEnv(a.substr(8));
+#else
+ env.UnPutEnv(a.substr(8));
+#endif
+ } else if (a == "--modify") {
+#ifdef CMAKE_BOOTSTRAP
+ std::cerr
+ << "cmake -E env: --modify not available during bootstrapping\n";
+ return 1;
+#else
+ if (++ai == ae) {
+ std::cerr << "cmake -E env: --modify missing a parameter\n";
+ return 1;
+ }
+ std::string const& op = *ai;
+ if (!env.ParseOperation(op)) {
+ std::cerr << "cmake -E env: invalid parameter to --modify: " << op
+ << '\n';
+ return 1;
+ }
+#endif
} else if (!a.empty() && a[0] == '-') {
// Environment variable and command names cannot start in '-',
// so this must be an unknown option.
- std::cerr << "cmake -E env: unknown option '" << a << '\''
- << std::endl;
+ std::cerr << "cmake -E env: unknown option '" << a << "'\n";
return 1;
} else if (a.find('=') != std::string::npos) {
// Set environment variable.
+#ifdef CMAKE_BOOTSTRAP
cmSystemTools::PutEnv(a);
+#else
+ env.PutEnv(a);
+#endif
} else {
// This is the beginning of the command.
break;
@@ -820,10 +848,14 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
}
if (ai == ae) {
- std::cerr << "cmake -E env: no command given" << std::endl;
+ std::cerr << "cmake -E env: no command given\n";
return 1;
}
+#ifndef CMAKE_BOOTSTRAP
+ env.ApplyToCurrentEnv();
+#endif
+
// Execute command from remaining arguments.
std::vector<std::string> cmd(ai, ae);
int retval;
@@ -2242,13 +2274,18 @@ bool cmVSLink::Parse(std::vector<std::string>::const_iterator argBeg,
// Parse the link command to extract information we need.
for (; arg != argEnd; ++arg) {
if (cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL:YES") == 0 ||
- cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL") == 0) {
+ cmSystemTools::Strucmp(arg->c_str(), "-INCREMENTAL:YES") == 0 ||
+ cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL") == 0 ||
+ cmSystemTools::Strucmp(arg->c_str(), "-INCREMENTAL") == 0) {
this->Incremental = true;
- } else if (cmSystemTools::Strucmp(arg->c_str(), "/MANIFEST:NO") == 0) {
+ } else if (cmSystemTools::Strucmp(arg->c_str(), "/MANIFEST:NO") == 0 ||
+ cmSystemTools::Strucmp(arg->c_str(), "-MANIFEST:NO") == 0) {
this->LinkGeneratesManifest = false;
- } else if (cmHasLiteralPrefix(*arg, "/Fe")) {
+ } else if (cmHasLiteralPrefix(*arg, "/Fe") ||
+ cmHasLiteralPrefix(*arg, "-Fe")) {
this->TargetFile = arg->substr(3);
- } else if (cmHasLiteralPrefix(*arg, "/out:")) {
+ } else if (cmHasLiteralPrefix(*arg, "/out:") ||
+ cmHasLiteralPrefix(*arg, "-out:")) {
this->TargetFile = arg->substr(5);
}
}
diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx
index d520c14..f239576 100644
--- a/Source/kwsys/Directory.cxx
+++ b/Source/kwsys/Directory.cxx
@@ -43,12 +43,12 @@ public:
{
std::string Name;
#if defined(_WIN32) && !defined(__CYGWIN__)
- _wfinddata_t FindData;
+ WIN32_FIND_DATAW FindData;
#endif
FileData(std::string name
#if defined(_WIN32) && !defined(__CYGWIN__)
,
- _wfinddata_t data
+ WIN32_FIND_DATAW data
#endif
)
: Name(std::move(name))
@@ -115,8 +115,8 @@ std::string Directory::GetFilePath(std::size_t i) const
bool Directory::FileIsDirectory(std::size_t i) const
{
#if defined(_WIN32) && !defined(__CYGWIN__)
- _wfinddata_t const& data = this->Internal->Files[i].FindData;
- return (data.attrib & FILE_ATTRIBUTE_DIRECTORY) != 0;
+ auto const& data = this->Internal->Files[i].FindData;
+ return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
#else
std::string const& path = this->GetFilePath(i);
return kwsys::SystemTools::FileIsDirectory(path);
@@ -127,9 +127,9 @@ bool Directory::FileIsSymlink(std::size_t i) const
{
std::string const& path = this->GetFilePath(i);
#if defined(_WIN32) && !defined(__CYGWIN__)
- _wfinddata_t const& data = this->Internal->Files[i].FindData;
+ auto const& data = this->Internal->Files[i].FindData;
return kwsys::SystemTools::FileIsSymlinkWithAttr(
- Encoding::ToWindowsExtendedPath(path), data.attrib);
+ Encoding::ToWindowsExtendedPath(path), data.dwFileAttributes);
#else
return kwsys::SystemTools::FileIsSymlink(path);
#endif
@@ -157,7 +157,7 @@ namespace KWSYS_NAMESPACE {
Status Directory::Load(std::string const& name, std::string* errorMessage)
{
this->Clear();
- intptr_t srchHandle;
+ HANDLE srchHandle;
char* buf;
size_t bufLength;
size_t n = name.size();
@@ -176,14 +176,14 @@ Status Directory::Load(std::string const& name, std::string* errorMessage)
snprintf(buf, bufLength, "%s/*", name.c_str());
}
}
- struct _wfinddata_t data; // data of current file
+ WIN32_FIND_DATAW data; // data of current file
// Now put them into the file array
srchHandle =
- _wfindfirst((wchar_t*)Encoding::ToWindowsExtendedPath(buf).c_str(), &data);
+ FindFirstFileW(Encoding::ToWindowsExtendedPath(buf).c_str(), &data);
delete[] buf;
- if (srchHandle == -1) {
+ if (srchHandle == INVALID_HANDLE_VALUE) {
Status status = Status::POSIX_errno();
if (errorMessage) {
*errorMessage = status.GetString();
@@ -193,10 +193,11 @@ Status Directory::Load(std::string const& name, std::string* errorMessage)
// Loop through names
do {
- this->Internal->Files.emplace_back(Encoding::ToNarrow(data.name), data);
- } while (_wfindnext(srchHandle, &data) != -1);
+ this->Internal->Files.emplace_back(Encoding::ToNarrow(data.cFileName),
+ data);
+ } while (FindNextFileW(srchHandle, &data));
this->Internal->Path = name;
- if (_findclose(srchHandle) == -1) {
+ if (!FindClose(srchHandle)) {
Status status = Status::POSIX_errno();
if (errorMessage) {
*errorMessage = status.GetString();
@@ -209,7 +210,7 @@ Status Directory::Load(std::string const& name, std::string* errorMessage)
unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name,
std::string* errorMessage)
{
- intptr_t srchHandle;
+ HANDLE srchHandle;
char* buf;
size_t bufLength;
size_t n = name.size();
@@ -222,13 +223,13 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name,
buf = new char[n + 2 + 1];
snprintf(buf, bufLength, "%s/*", name.c_str());
}
- struct _wfinddata_t data; // data of current file
+ WIN32_FIND_DATAW data; // data of current file
// Now put them into the file array
- srchHandle = _wfindfirst((wchar_t*)Encoding::ToWide(buf).c_str(), &data);
+ srchHandle = FindFirstFileW(Encoding::ToWide(buf).c_str(), &data);
delete[] buf;
- if (srchHandle == -1) {
+ if (srchHandle == INVALID_HANDLE_VALUE) {
if (errorMessage) {
if (unsigned int errorId = GetLastError()) {
LPSTR message = nullptr;
@@ -250,8 +251,8 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name,
unsigned long count = 0;
do {
count++;
- } while (_wfindnext(srchHandle, &data) != -1);
- _findclose(srchHandle);
+ } while (FindNextFileW(srchHandle, &data));
+ FindClose(srchHandle);
return count;
}
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 89a3cc7..a20901c 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -536,9 +536,11 @@ public:
StringMap TranslationMap;
#endif
#ifdef _WIN32
- static std::string GetCasePathName(std::string const& pathIn);
+ static std::string GetCasePathName(std::string const& pathIn,
+ bool const cache);
static std::string GetActualCaseForPathCached(std::string const& path);
static const char* GetEnvBuffered(const char* key);
+ std::map<std::string, std::string, SystemToolsPathCaseCmp> FindFileMap;
std::map<std::string, std::string, SystemToolsPathCaseCmp> PathCaseMap;
std::map<std::string, std::string> EnvMap;
#endif
@@ -571,7 +573,8 @@ public:
static SystemToolsStatic* SystemToolsStatics;
#ifdef _WIN32
-std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn)
+std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn,
+ bool const cache)
{
std::string casePath;
@@ -623,14 +626,31 @@ std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn)
} else {
std::string test_str = casePath;
test_str += path_components[idx];
- WIN32_FIND_DATAW findData;
- HANDLE hFind =
- ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData);
- if (INVALID_HANDLE_VALUE != hFind) {
- path_components[idx] = Encoding::ToNarrow(findData.cFileName);
- ::FindClose(hFind);
- } else {
- converting = false;
+
+ bool found_in_cache = false;
+ if (cache) {
+ auto const it = SystemToolsStatics->FindFileMap.find(test_str);
+ if (it != SystemToolsStatics->FindFileMap.end()) {
+ path_components[idx] = it->second;
+ found_in_cache = true;
+ }
+ }
+
+ if (!found_in_cache) {
+ WIN32_FIND_DATAW findData;
+ HANDLE hFind =
+ ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData);
+ if (INVALID_HANDLE_VALUE != hFind) {
+ auto case_file_name = Encoding::ToNarrow(findData.cFileName);
+ if (cache) {
+ SystemToolsStatics->FindFileMap.emplace(test_str,
+ case_file_name);
+ }
+ path_components[idx] = std::move(case_file_name);
+ ::FindClose(hFind);
+ } else {
+ converting = false;
+ }
}
}
}
@@ -642,19 +662,16 @@ std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn)
std::string SystemToolsStatic::GetActualCaseForPathCached(std::string const& p)
{
- // Check to see if actual case has already been called
- // for this path, and the result is stored in the PathCaseMap
- auto& pcm = SystemToolsStatics->PathCaseMap;
- {
- auto itr = pcm.find(p);
- if (itr != pcm.end()) {
- return itr->second;
- }
- }
- std::string casePath = SystemToolsStatic::GetCasePathName(p);
- if (casePath.size() <= MAX_PATH) {
- pcm[p] = casePath;
+ std::string casePath;
+
+ auto it = SystemToolsStatics->PathCaseMap.find(p);
+ if (it != SystemToolsStatics->PathCaseMap.end()) {
+ casePath = it->second;
+ } else {
+ casePath = SystemToolsStatic::GetCasePathName(p, true);
+ SystemToolsStatics->PathCaseMap.emplace(p, casePath);
}
+
return casePath;
}
#endif
@@ -3677,7 +3694,7 @@ std::string SystemTools::RelativePath(const std::string& local,
std::string SystemTools::GetActualCaseForPath(const std::string& p)
{
#ifdef _WIN32
- return SystemToolsStatic::GetCasePathName(p);
+ return SystemToolsStatic::GetCasePathName(p, false);
#else
return p;
#endif