summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeInstallSignTool.cmake.in51
-rw-r--r--Source/CMakeLists.txt65
-rw-r--r--Source/CMakeVersion.cmake4
-rw-r--r--Source/CMakeVersion.rc.in19
-rw-r--r--Source/CPack/IFW/cmCPackIFWGenerator.cxx8
-rw-r--r--Source/CPack/IFW/cmCPackIFWInstaller.cxx17
-rw-r--r--Source/CPack/IFW/cmCPackIFWInstaller.h3
-rw-r--r--Source/CPack/OSXScriptLauncher.cxx2
-rw-r--r--Source/CPack/WiX/cmCPackWIXGenerator.cxx7
-rw-r--r--Source/CPack/bills-comments.txt68
-rw-r--r--Source/CPack/cmCPackCygwinBinaryGenerator.cxx5
-rw-r--r--Source/CPack/cmCPackDebGenerator.cxx2
-rw-r--r--Source/CPack/cmCPackDragNDropGenerator.cxx4
-rw-r--r--Source/CPack/cmCPackFreeBSDGenerator.cxx5
-rw-r--r--Source/CPack/cmCPackGenerator.cxx21
-rw-r--r--Source/CPack/cmCPackGenerator.h5
-rw-r--r--Source/CPack/cmCPackGeneratorFactory.h3
-rw-r--r--Source/CPack/cmCPackLog.h3
-rw-r--r--Source/CPack/cmCPackNSISGenerator.cxx41
-rw-r--r--Source/CPack/cmCPackOSXX11Generator.cxx10
-rw-r--r--Source/CPack/cmCPackPKGGenerator.cxx60
-rw-r--r--Source/CPack/cmCPackPackageMakerGenerator.cxx4
-rw-r--r--Source/CPack/cmCPackProductBuildGenerator.cxx4
-rw-r--r--Source/CPack/cpack.cxx5
-rw-r--r--Source/CTest/cmCTestBZR.cxx5
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.cxx17
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.h2
-rw-r--r--Source/CTest/cmCTestBuildCommand.cxx11
-rw-r--r--Source/CTest/cmCTestBuildHandler.cxx70
-rw-r--r--Source/CTest/cmCTestBuildHandler.h2
-rw-r--r--Source/CTest/cmCTestCVS.cxx2
-rw-r--r--Source/CTest/cmCTestConfigureCommand.cxx11
-rw-r--r--Source/CTest/cmCTestConfigureHandler.cxx2
-rw-r--r--Source/CTest/cmCTestCoverageCommand.cxx8
-rw-r--r--Source/CTest/cmCTestCoverageHandler.cxx39
-rw-r--r--Source/CTest/cmCTestCurl.cxx9
-rw-r--r--Source/CTest/cmCTestCurl.h2
-rw-r--r--Source/CTest/cmCTestGIT.cxx4
-rw-r--r--Source/CTest/cmCTestGlobalVC.cxx5
-rw-r--r--Source/CTest/cmCTestGlobalVC.h2
-rw-r--r--Source/CTest/cmCTestHG.cxx5
-rw-r--r--Source/CTest/cmCTestHandlerCommand.cxx2
-rw-r--r--Source/CTest/cmCTestLaunch.cxx2
-rw-r--r--Source/CTest/cmCTestLaunch.h3
-rw-r--r--Source/CTest/cmCTestMemCheckCommand.cxx5
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.cxx14
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.h6
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.cxx25
-rw-r--r--Source/CTest/cmCTestP4.cxx16
-rw-r--r--Source/CTest/cmCTestRunTest.cxx123
-rw-r--r--Source/CTest/cmCTestRunTest.h5
-rw-r--r--Source/CTest/cmCTestSVN.cxx15
-rw-r--r--Source/CTest/cmCTestScriptHandler.cxx44
-rw-r--r--Source/CTest/cmCTestSubmitCommand.cxx78
-rw-r--r--Source/CTest/cmCTestSubmitCommand.h30
-rw-r--r--Source/CTest/cmCTestSubmitHandler.cxx50
-rw-r--r--Source/CTest/cmCTestSubmitHandler.h4
-rw-r--r--Source/CTest/cmCTestTestCommand.cxx5
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx6
-rw-r--r--Source/CTest/cmCTestTestHandler.h7
-rw-r--r--Source/CTest/cmCTestUpdateCommand.cxx13
-rw-r--r--Source/CTest/cmCTestUpdateHandler.cxx4
-rw-r--r--Source/CTest/cmCTestUploadCommand.cxx12
-rw-r--r--Source/CTest/cmCTestUploadCommand.h6
-rw-r--r--Source/CTest/cmCTestUploadHandler.cxx5
-rw-r--r--Source/CTest/cmCTestUploadHandler.h9
-rw-r--r--Source/CTest/cmCTestVC.cxx14
-rw-r--r--Source/CTest/cmCTestVC.h1
-rw-r--r--Source/CTest/cmProcess.cxx67
-rw-r--r--Source/CTest/cmProcess.h9
-rw-r--r--Source/Checks/cm_cxx17_check.cpp13
-rw-r--r--Source/CursesDialog/ccmake.cxx3
-rw-r--r--Source/CursesDialog/cmCursesCacheEntryComposite.cxx2
-rw-r--r--Source/CursesDialog/cmCursesForm.h4
-rw-r--r--Source/CursesDialog/cmCursesLongMessageForm.cxx5
-rw-r--r--Source/CursesDialog/cmCursesMainForm.cxx145
-rw-r--r--Source/CursesDialog/cmCursesMainForm.h4
-rw-r--r--Source/LexerParser/cmCommandArgumentParser.cxx2
-rw-r--r--Source/QtDialog/CMakeLists.txt3
-rw-r--r--Source/QtDialog/CMakeSetup.cxx1
-rw-r--r--Source/QtDialog/CMakeSetupDialog.cxx2
-rw-r--r--Source/QtDialog/FirstConfigure.cxx23
-rw-r--r--Source/QtDialog/QCMake.cxx47
-rw-r--r--Source/QtDialog/QCMake.h4
-rw-r--r--Source/QtDialog/RegexExplorer.cxx2
-rw-r--r--Source/cmAddCustomCommandCommand.cxx19
-rw-r--r--Source/cmAddCustomTargetCommand.cxx14
-rw-r--r--Source/cmAddDependenciesCommand.cxx9
-rw-r--r--Source/cmAddLibraryCommand.cxx7
-rw-r--r--Source/cmAddSubDirectoryCommand.cxx9
-rw-r--r--Source/cmAddTestCommand.cxx3
-rw-r--r--Source/cmAlgorithms.h117
-rw-r--r--Source/cmArchiveWrite.cxx20
-rw-r--r--Source/cmArchiveWrite.h6
-rw-r--r--Source/cmArgumentParser.cxx93
-rw-r--r--Source/cmArgumentParser.h143
-rw-r--r--Source/cmCMakeMinimumRequired.cxx2
-rw-r--r--Source/cmCMakePolicyCommand.cxx2
-rw-r--r--Source/cmCPluginAPI.cxx32
-rw-r--r--Source/cmCTest.cxx1148
-rw-r--r--Source/cmCTest.h266
-rw-r--r--Source/cmCacheManager.cxx10
-rw-r--r--Source/cmCacheManager.h24
-rw-r--r--Source/cmCallVisualStudioMacro.cxx42
-rw-r--r--Source/cmCallVisualStudioMacro.h12
-rw-r--r--Source/cmCommandArgumentsHelper.cxx233
-rw-r--r--Source/cmCommandArgumentsHelper.h194
-rw-r--r--Source/cmComputeLinkDepends.cxx19
-rw-r--r--Source/cmComputeLinkDepends.h3
-rw-r--r--Source/cmComputeLinkInformation.cxx6
-rw-r--r--Source/cmComputeTargetDepends.cxx6
-rw-r--r--Source/cmConditionEvaluator.cxx11
-rw-r--r--Source/cmConfigureFileCommand.cxx6
-rw-r--r--Source/cmCoreTryCompile.cxx30
-rw-r--r--Source/cmCreateTestSourceList.cxx3
-rw-r--r--Source/cmCustomCommand.cxx19
-rw-r--r--Source/cmCustomCommand.h5
-rw-r--r--Source/cmCustomCommandGenerator.cxx69
-rw-r--r--Source/cmCustomCommandGenerator.h7
-rw-r--r--Source/cmDepends.cxx191
-rw-r--r--Source/cmDepends.h29
-rw-r--r--Source/cmDependsC.cxx50
-rw-r--r--Source/cmDependsC.h5
-rw-r--r--Source/cmDependsFortran.cxx2
-rw-r--r--Source/cmDependsJava.cxx3
-rw-r--r--Source/cmDependsJava.h7
-rw-r--r--Source/cmDependsJavaParserHelper.cxx13
-rw-r--r--Source/cmDependsJavaParserHelper.h4
-rw-r--r--Source/cmDocumentationSection.h3
-rw-r--r--Source/cmELF.cxx3
-rw-r--r--Source/cmELF.h3
-rw-r--r--Source/cmExecProgramCommand.cxx34
-rw-r--r--Source/cmExecProgramCommand.h2
-rw-r--r--Source/cmExecuteProcessCommand.cxx339
-rw-r--r--Source/cmExportBuildFileGenerator.h3
-rw-r--r--Source/cmExportCommand.cxx131
-rw-r--r--Source/cmExportCommand.h24
-rw-r--r--Source/cmExportFileGenerator.cxx3
-rw-r--r--Source/cmExportLibraryDependenciesCommand.cxx8
-rw-r--r--Source/cmExportSet.h3
-rw-r--r--Source/cmExportSetMap.cxx2
-rw-r--r--Source/cmExportSetMap.h5
-rw-r--r--Source/cmExternalMakefileProjectGenerator.h10
-rw-r--r--Source/cmExtraCodeBlocksGenerator.cxx82
-rw-r--r--Source/cmExtraCodeBlocksGenerator.h7
-rw-r--r--Source/cmExtraCodeLiteGenerator.cxx8
-rw-r--r--Source/cmExtraEclipseCDT4Generator.cxx7
-rw-r--r--Source/cmExtraKateGenerator.cxx6
-rw-r--r--Source/cmExtraSublimeTextGenerator.cxx10
-rw-r--r--Source/cmFLTKWrapUICommand.cxx10
-rw-r--r--Source/cmFileAPI.cxx63
-rw-r--r--Source/cmFileAPI.h5
-rw-r--r--Source/cmFileAPICodemodel.cxx4
-rw-r--r--Source/cmFileCommand.cxx1409
-rw-r--r--Source/cmFileCopier.cxx713
-rw-r--r--Source/cmFileCopier.h122
-rw-r--r--Source/cmFileInstaller.cxx350
-rw-r--r--Source/cmFileInstaller.h55
-rw-r--r--Source/cmFilePathChecksum.cxx2
-rw-r--r--Source/cmFileTime.cxx49
-rw-r--r--Source/cmFileTime.h130
-rw-r--r--Source/cmFileTimeCache.cxx62
-rw-r--r--Source/cmFileTimeCache.h56
-rw-r--r--Source/cmFileTimeComparison.cxx233
-rw-r--r--Source/cmFileTimeComparison.h42
-rw-r--r--Source/cmFileTimes.cxx127
-rw-r--r--Source/cmFileTimes.h40
-rw-r--r--Source/cmFindBase.cxx13
-rw-r--r--Source/cmFindCommon.cxx5
-rw-r--r--Source/cmFindPackageCommand.cxx152
-rw-r--r--Source/cmFindPackageCommand.h12
-rw-r--r--Source/cmForEachCommand.cxx7
-rw-r--r--Source/cmFortranParser.h3
-rw-r--r--Source/cmFortranParserImpl.cxx8
-rw-r--r--Source/cmFunctionCommand.cxx3
-rw-r--r--Source/cmGeneratedFileStream.cxx6
-rw-r--r--Source/cmGeneratorExpressionEvaluator.cxx37
-rw-r--r--Source/cmGeneratorExpressionNode.cxx1228
-rw-r--r--Source/cmGeneratorExpressionNode.h4
-rw-r--r--Source/cmGeneratorExpressionParser.cxx11
-rw-r--r--Source/cmGeneratorTarget.cxx578
-rw-r--r--Source/cmGeneratorTarget.h44
-rw-r--r--Source/cmGetPipes.cxx48
-rw-r--r--Source/cmGetPipes.h8
-rw-r--r--Source/cmGhsMultiGpj.cxx10
-rw-r--r--Source/cmGhsMultiGpj.h9
-rw-r--r--Source/cmGhsMultiTargetGenerator.cxx539
-rw-r--r--Source/cmGhsMultiTargetGenerator.h34
-rw-r--r--Source/cmGlobVerificationManager.cxx8
-rw-r--r--Source/cmGlobVerificationManager.h12
-rw-r--r--Source/cmGlobalBorlandMakefileGenerator.cxx19
-rw-r--r--Source/cmGlobalBorlandMakefileGenerator.h19
-rw-r--r--Source/cmGlobalGenerator.cxx449
-rw-r--r--Source/cmGlobalGenerator.h64
-rw-r--r--Source/cmGlobalGhsMultiGenerator.cxx569
-rw-r--r--Source/cmGlobalGhsMultiGenerator.h105
-rw-r--r--Source/cmGlobalJOMMakefileGenerator.cxx20
-rw-r--r--Source/cmGlobalJOMMakefileGenerator.h17
-rw-r--r--Source/cmGlobalMSYSMakefileGenerator.cxx9
-rw-r--r--Source/cmGlobalMSYSMakefileGenerator.h2
-rw-r--r--Source/cmGlobalMinGWMakefileGenerator.cxx3
-rw-r--r--Source/cmGlobalMinGWMakefileGenerator.h2
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.cxx20
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.h17
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx1164
-rw-r--r--Source/cmGlobalNinjaGenerator.h121
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.cxx196
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.h20
-rw-r--r--Source/cmGlobalVisualStudio10Generator.cxx147
-rw-r--r--Source/cmGlobalVisualStudio10Generator.h22
-rw-r--r--Source/cmGlobalVisualStudio11Generator.cxx11
-rw-r--r--Source/cmGlobalVisualStudio11Generator.h4
-rw-r--r--Source/cmGlobalVisualStudio14Generator.cxx2
-rw-r--r--Source/cmGlobalVisualStudio7Generator.cxx74
-rw-r--r--Source/cmGlobalVisualStudio7Generator.h25
-rw-r--r--Source/cmGlobalVisualStudio8Generator.cxx43
-rw-r--r--Source/cmGlobalVisualStudio8Generator.h12
-rw-r--r--Source/cmGlobalVisualStudioGenerator.cxx45
-rw-r--r--Source/cmGlobalVisualStudioVersionedGenerator.cxx6
-rw-r--r--Source/cmGlobalWatcomWMakeGenerator.cxx18
-rw-r--r--Source/cmGlobalWatcomWMakeGenerator.h17
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx248
-rw-r--r--Source/cmGlobalXCodeGenerator.h34
-rw-r--r--Source/cmGraphVizWriter.cxx26
-rw-r--r--Source/cmGraphVizWriter.h10
-rw-r--r--Source/cmHexFileConverter.cxx6
-rw-r--r--Source/cmHexFileConverter.h6
-rw-r--r--Source/cmIDEOptions.cxx6
-rw-r--r--Source/cmIncludeDirectoryCommand.cxx7
-rw-r--r--Source/cmInstallCommand.cxx175
-rw-r--r--Source/cmInstallCommandArguments.cxx72
-rw-r--r--Source/cmInstallCommandArguments.h35
-rw-r--r--Source/cmInstallDirectoryGenerator.cxx15
-rw-r--r--Source/cmInstallDirectoryGenerator.h2
-rw-r--r--Source/cmInstallExportAndroidMKGenerator.cxx19
-rw-r--r--Source/cmInstallExportAndroidMKGenerator.h2
-rw-r--r--Source/cmInstallExportGenerator.cxx5
-rw-r--r--Source/cmInstallExportGenerator.h2
-rw-r--r--Source/cmInstallFilesCommand.cxx10
-rw-r--r--Source/cmInstallFilesGenerator.cxx15
-rw-r--r--Source/cmInstallFilesGenerator.h2
-rw-r--r--Source/cmInstallGenerator.cxx11
-rw-r--r--Source/cmInstallGenerator.h2
-rw-r--r--Source/cmInstallProgramsCommand.cxx3
-rw-r--r--Source/cmInstallScriptGenerator.cxx4
-rw-r--r--Source/cmInstallScriptGenerator.h2
-rw-r--r--Source/cmInstallSubdirectoryGenerator.cxx3
-rw-r--r--Source/cmInstallSubdirectoryGenerator.h2
-rw-r--r--Source/cmInstallTargetGenerator.cxx106
-rw-r--r--Source/cmInstallTargetGenerator.h2
-rw-r--r--Source/cmInstallTargetsCommand.cxx8
-rw-r--r--Source/cmInstalledFile.h6
-rw-r--r--Source/cmJsonObjects.cxx4
-rw-r--r--Source/cmLinkLineDeviceComputer.cxx91
-rw-r--r--Source/cmLinkLineDeviceComputer.h22
-rw-r--r--Source/cmListCommand.cxx139
-rw-r--r--Source/cmListCommand.h3
-rw-r--r--Source/cmListFileCache.cxx9
-rw-r--r--Source/cmLoadCommandCommand.cxx2
-rw-r--r--Source/cmLocalGenerator.cxx281
-rw-r--r--Source/cmLocalGenerator.h16
-rw-r--r--Source/cmLocalGhsMultiGenerator.cxx13
-rw-r--r--Source/cmLocalGhsMultiGenerator.h13
-rw-r--r--Source/cmLocalNinjaGenerator.cxx84
-rw-r--r--Source/cmLocalNinjaGenerator.h2
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx155
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.h13
-rw-r--r--Source/cmLocalVisualStudio10Generator.h2
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx170
-rw-r--r--Source/cmLocalVisualStudio7Generator.h2
-rw-r--r--Source/cmLocalVisualStudioGenerator.cxx1
-rw-r--r--Source/cmLocalXCodeGenerator.h2
-rw-r--r--Source/cmMacroCommand.cxx3
-rw-r--r--Source/cmMakefile.cxx169
-rw-r--r--Source/cmMakefile.h60
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx84
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx148
-rw-r--r--Source/cmMakefileTargetGenerator.cxx121
-rw-r--r--Source/cmMakefileTargetGenerator.h12
-rw-r--r--Source/cmMakefileUtilityTargetGenerator.cxx9
-rw-r--r--Source/cmMessageCommand.cxx55
-rw-r--r--Source/cmNinjaLinkLineDeviceComputer.cxx20
-rw-r--r--Source/cmNinjaLinkLineDeviceComputer.h34
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx623
-rw-r--r--Source/cmNinjaNormalTargetGenerator.h9
-rw-r--r--Source/cmNinjaTargetGenerator.cxx736
-rw-r--r--Source/cmNinjaTargetGenerator.h21
-rw-r--r--Source/cmNinjaTypes.h41
-rw-r--r--Source/cmNinjaUtilityTargetGenerator.cxx134
-rw-r--r--Source/cmOSXBundleGenerator.cxx8
-rw-r--r--Source/cmOrderDirectories.cxx6
-rw-r--r--Source/cmOrderDirectories.h2
-rw-r--r--Source/cmOutputConverter.h2
-rw-r--r--Source/cmOutputRequiredFilesCommand.cxx16
-rw-r--r--Source/cmParseArgumentsCommand.cxx204
-rw-r--r--Source/cmPolicies.cxx8
-rw-r--r--Source/cmPolicies.h32
-rw-r--r--Source/cmProjectCommand.cxx48
-rw-r--r--Source/cmProjectCommand.h1
-rw-r--r--Source/cmQTWrapCPPCommand.cxx15
-rw-r--r--Source/cmQTWrapUICommand.cxx15
-rw-r--r--Source/cmQtAutoGen.cxx202
-rw-r--r--Source/cmQtAutoGen.h95
-rw-r--r--Source/cmQtAutoGenGlobalInitializer.cxx67
-rw-r--r--Source/cmQtAutoGenGlobalInitializer.h41
-rw-r--r--Source/cmQtAutoGenInitializer.cxx999
-rw-r--r--Source/cmQtAutoGenInitializer.h100
-rw-r--r--Source/cmQtAutoGenerator.cxx613
-rw-r--r--Source/cmQtAutoGenerator.h247
-rw-r--r--Source/cmQtAutoGeneratorMocUic.cxx2042
-rw-r--r--Source/cmQtAutoGeneratorMocUic.h450
-rw-r--r--Source/cmQtAutoGeneratorRcc.cxx672
-rw-r--r--Source/cmQtAutoMocUic.cxx2193
-rw-r--r--Source/cmQtAutoMocUic.h576
-rw-r--r--Source/cmQtAutoRcc.cxx523
-rw-r--r--Source/cmQtAutoRcc.h (renamed from Source/cmQtAutoGeneratorRcc.h)73
-rw-r--r--Source/cmRST.cxx9
-rw-r--r--Source/cmRange.h239
-rw-r--r--Source/cmRemoveCommand.cxx10
-rw-r--r--Source/cmRulePlaceholderExpander.cxx35
-rw-r--r--Source/cmRulePlaceholderExpander.h5
-rw-r--r--Source/cmSearchPath.cxx4
-rw-r--r--Source/cmServer.cxx11
-rw-r--r--Source/cmServer.h4
-rw-r--r--Source/cmServerConnection.cxx4
-rw-r--r--Source/cmServerProtocol.cxx7
-rw-r--r--Source/cmSetCommand.cxx1
-rw-r--r--Source/cmSetPropertyCommand.cxx37
-rw-r--r--Source/cmSetTargetPropertiesCommand.cxx3
-rw-r--r--Source/cmSetTestsPropertiesCommand.cxx3
-rw-r--r--Source/cmSiteNameCommand.cxx5
-rw-r--r--Source/cmSourceFile.h11
-rw-r--r--Source/cmSourceGroupCommand.cxx6
-rw-r--r--Source/cmState.cxx19
-rw-r--r--Source/cmState.h5
-rw-r--r--Source/cmStateDirectory.cxx16
-rw-r--r--Source/cmStringCommand.cxx64
-rw-r--r--Source/cmStringCommand.h1
-rw-r--r--Source/cmSystemTools.cxx454
-rw-r--r--Source/cmSystemTools.h139
-rw-r--r--Source/cmTarget.cxx1052
-rw-r--r--Source/cmTarget.h236
-rw-r--r--Source/cmTargetPropertyComputer.cxx3
-rw-r--r--Source/cmTargetPropertyComputer.h2
-rw-r--r--Source/cmTest.h4
-rw-r--r--Source/cmTestGenerator.cxx17
-rw-r--r--Source/cmTryRunCommand.cxx34
-rw-r--r--Source/cmUVHandlePtr.cxx62
-rw-r--r--Source/cmUVHandlePtr.h40
-rw-r--r--Source/cmUVProcessChain.cxx395
-rw-r--r--Source/cmUVProcessChain.h100
-rw-r--r--Source/cmUVStreambuf.h219
-rw-r--r--Source/cmUseMangledMesaCommand.cxx22
-rw-r--r--Source/cmUseMangledMesaCommand.h3
-rw-r--r--Source/cmUtilitySourceCommand.cxx2
-rw-r--r--Source/cmUuid.cxx18
-rw-r--r--Source/cmUuid.h4
-rw-r--r--Source/cmVariableWatch.h3
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx220
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h6
-rw-r--r--Source/cmVisualStudioGeneratorOptions.cxx15
-rw-r--r--Source/cmWorkerPool.cxx763
-rw-r--r--Source/cmWorkerPool.h226
-rw-r--r--Source/cmWorkingDirectory.h3
-rw-r--r--Source/cmXCodeScheme.cxx5
-rw-r--r--Source/cmXMLWriter.cxx2
-rw-r--r--Source/cmXMLWriter.h5
-rw-r--r--Source/cm_utf8.c29
-rw-r--r--Source/cm_utf8.h4
-rw-r--r--Source/cmake.cxx265
-rw-r--r--Source/cmake.h159
-rw-r--r--Source/cmakemain.cxx247
-rw-r--r--Source/cmakexbuild.cxx80
-rw-r--r--Source/cmcldeps.cxx2
-rw-r--r--Source/cmcmd.cxx335
-rw-r--r--Source/cmcmd.h14
-rw-r--r--Source/ctest.cxx4
-rw-r--r--Source/kwsys/CMakeLists.txt76
-rw-r--r--Source/kwsys/CommandLineArguments.hxx.in3
-rw-r--r--Source/kwsys/Configure.h.in37
-rw-r--r--Source/kwsys/Configure.hxx.in5
-rw-r--r--Source/kwsys/Directory.cxx4
-rw-r--r--Source/kwsys/DynamicLoader.cxx110
-rw-r--r--Source/kwsys/DynamicLoader.hxx.in15
-rw-r--r--Source/kwsys/Glob.cxx2
-rw-r--r--Source/kwsys/Glob.hxx.in14
-rw-r--r--Source/kwsys/ProcessWin32.c23
-rw-r--r--Source/kwsys/SystemInformation.cxx109
-rw-r--r--Source/kwsys/SystemInformation.hxx.in3
-rw-r--r--Source/kwsys/SystemTools.cxx533
-rw-r--r--Source/kwsys/SystemTools.hxx.in46
-rw-r--r--Source/kwsys/hashtable.hxx.in2
-rw-r--r--Source/kwsys/kwsysPlatformTestsCXX.cxx42
-rw-r--r--Source/kwsys/testConsoleBuf.cxx9
-rw-r--r--Source/kwsys/testDynamicLoader.cxx28
-rw-r--r--Source/kwsys/testDynloadImpl.c10
-rw-r--r--Source/kwsys/testDynloadImpl.h15
-rw-r--r--Source/kwsys/testDynloadUse.c15
398 files changed, 19477 insertions, 15246 deletions
diff --git a/Source/CMakeInstallSignTool.cmake.in b/Source/CMakeInstallSignTool.cmake.in
new file mode 100644
index 000000000..fca629c31
--- /dev/null
+++ b/Source/CMakeInstallSignTool.cmake.in
@@ -0,0 +1,51 @@
+# The signtool. Default to PATH.
+set(CMake_INSTALL_SIGNTOOL "@CMake_INSTALL_SIGNTOOL@")
+if(NOT CMake_INSTALL_SIGNTOOL)
+ set(CMake_INSTALL_SIGNTOOL signtool)
+endif()
+
+# Select a certificate by Subject Name. Default to automatic selection.
+set(CMake_INSTALL_SIGNTOOL_SUBJECT_NAME "@CMake_INSTALL_SIGNTOOL_SUBJECT_NAME@")
+if(CMake_INSTALL_SIGNTOOL_SUBJECT_NAME)
+ set(select_cert -n "${CMake_INSTALL_SIGNTOOL_SUBJECT_NAME}")
+else()
+ set(select_cert -a)
+endif()
+
+# Timestamp URL. Default to a common provider.
+set(CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL "@CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL@")
+if(NOT CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL)
+ set(CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL "http://timestamp.digicert.com")
+endif()
+
+# Glob files that need a signature.
+file(GLOB files "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/*.exe")
+
+# Sign all files at once.
+if(files)
+ # Run the signtool through 'cmd /c' to enable password prompt popup.
+ # Some providers have trouble when signtool is invoked with SW_HIDE.
+ set(cmd cmd /c "${CMake_INSTALL_SIGNTOOL}" sign -v ${select_cert})
+
+ # Sign with SHA-1 for Windows 7 and below.
+ execute_process(
+ COMMAND ${cmd} -t "${CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL}" ${files}
+ RESULT_VARIABLE result
+ ERROR_VARIABLE stderr
+ )
+ if(NOT result EQUAL 0)
+ string(REPLACE "\n" "\n " stderr " ${stderr}")
+ message(WARNING "signtool failed:\n${stderr}")
+ endif()
+
+ # Sign with SHA-256 for Windows 8 and above.
+ execute_process(
+ COMMAND ${cmd} -tr "${CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL}" -fd sha256 -td sha256 -as ${files}
+ RESULT_VARIABLE result
+ ERROR_VARIABLE stderr
+ )
+ if(NOT result EQUAL 0)
+ string(REPLACE "\n" "\n " stderr " ${stderr}")
+ message(WARNING "signtool failed:\n${stderr}")
+ endif()
+endif()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 1c06052fd..695e07598 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -92,7 +92,6 @@ include_directories(
${CMAKE_ZLIB_INCLUDES}
${CMAKE_EXPAT_INCLUDES}
${CMAKE_TAR_INCLUDES}
- ${CMAKE_COMPRESS_INCLUDES}
${CMake_HAIKU_INCLUDE_DIRS}
)
@@ -144,6 +143,8 @@ set(SRCS
cmAffinity.cxx
cmAffinity.h
cmArchiveWrite.cxx
+ cmArgumentParser.cxx
+ cmArgumentParser.h
cmBase32.cxx
cmCacheManager.cxx
cmCacheManager.h
@@ -225,6 +226,10 @@ set(SRCS
cmFileAPICodemodel.h
cmFileAPICMakeFiles.cxx
cmFileAPICMakeFiles.h
+ cmFileCopier.cxx
+ cmFileCopier.h
+ cmFileInstaller.cxx
+ cmFileInstaller.h
cmFileLock.cxx
cmFileLock.h
cmFileLockPool.cxx
@@ -233,8 +238,12 @@ set(SRCS
cmFileLockResult.h
cmFilePathChecksum.cxx
cmFilePathChecksum.h
- cmFileTimeComparison.cxx
- cmFileTimeComparison.h
+ cmFileTime.cxx
+ cmFileTime.h
+ cmFileTimeCache.cxx
+ cmFileTimeCache.h
+ cmFileTimes.cxx
+ cmFileTimes.h
cmFortranParserImpl.cxx
cmFSPermissions.cxx
cmFSPermissions.h
@@ -257,6 +266,8 @@ set(SRCS
cmGeneratorExpression.h
cmGeneratorTarget.cxx
cmGeneratorTarget.h
+ cmGetPipes.cxx
+ cmGetPipes.h
cmGlobalCommonGenerator.cxx
cmGlobalCommonGenerator.h
cmGlobalGenerator.cxx
@@ -343,10 +354,10 @@ set(SRCS
cmQtAutoGenGlobalInitializer.h
cmQtAutoGenInitializer.cxx
cmQtAutoGenInitializer.h
- cmQtAutoGeneratorMocUic.cxx
- cmQtAutoGeneratorMocUic.h
- cmQtAutoGeneratorRcc.cxx
- cmQtAutoGeneratorRcc.h
+ cmQtAutoMocUic.cxx
+ cmQtAutoMocUic.h
+ cmQtAutoRcc.cxx
+ cmQtAutoRcc.h
cmRST.cxx
cmRST.h
cmScriptGenerator.h
@@ -379,11 +390,16 @@ set(SRCS
cmUuid.cxx
cmUVHandlePtr.cxx
cmUVHandlePtr.h
+ cmUVProcessChain.cxx
+ cmUVProcessChain.h
+ cmUVStreambuf.h
cmUVSignalHackRAII.h
cmVariableWatch.cxx
cmVariableWatch.h
cmVersion.cxx
cmVersion.h
+ cmWorkerPool.cxx
+ cmWorkerPool.h
cmWorkingDirectory.cxx
cmWorkingDirectory.h
cmXMLParser.cxx
@@ -438,8 +454,6 @@ set(SRCS
cmCMakeMinimumRequired.h
cmCMakePolicyCommand.cxx
cmCMakePolicyCommand.h
- cmCommandArgumentsHelper.cxx
- cmCommandArgumentsHelper.h
cmConditionEvaluator.cxx
cmConditionEvaluator.h
cmConfigureFileCommand.cxx
@@ -724,14 +738,6 @@ if (WIN32)
cmVisualStudioSlnParser.cxx
cmVisualStudioWCEPlatformParser.h
cmVisualStudioWCEPlatformParser.cxx
- cmGlobalGhsMultiGenerator.cxx
- cmGlobalGhsMultiGenerator.h
- cmLocalGhsMultiGenerator.cxx
- cmLocalGhsMultiGenerator.h
- cmGhsMultiTargetGenerator.cxx
- cmGhsMultiTargetGenerator.h
- cmGhsMultiGpj.cxx
- cmGhsMultiGpj.h
cmVSSetupHelper.cxx
cmVSSetupHelper.h
)
@@ -751,6 +757,22 @@ if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
)
endif()
+# GHS support
+# Works only for windows and linux
+if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ set(SRCS ${SRCS}
+ cmGlobalGhsMultiGenerator.cxx
+ cmGlobalGhsMultiGenerator.h
+ cmLocalGhsMultiGenerator.cxx
+ cmLocalGhsMultiGenerator.h
+ cmGhsMultiTargetGenerator.cxx
+ cmGhsMultiTargetGenerator.h
+ cmGhsMultiGpj.cxx
+ cmGhsMultiGpj.h
+ )
+endif()
+
+
# Ninja support
set(SRCS ${SRCS}
cmGlobalNinjaGenerator.cxx
@@ -766,6 +788,8 @@ set(SRCS ${SRCS}
cmNinjaUtilityTargetGenerator.h
cmNinjaLinkLineComputer.cxx
cmNinjaLinkLineComputer.h
+ cmNinjaLinkLineDeviceComputer.cxx
+ cmNinjaLinkLineDeviceComputer.h
)
# Temporary variable for tools targets
@@ -793,7 +817,7 @@ foreach(check
else()
set(CMake_${check} 0)
endif()
- set_property(SOURCE cmFileTimeComparison.cxx APPEND PROPERTY
+ set_property(SOURCE cmFileTime.cxx APPEND PROPERTY
COMPILE_DEFINITIONS CMake_${check}=${CMake_${check}})
endforeach()
@@ -801,7 +825,7 @@ endforeach()
add_library(CMakeLib ${SRCS})
target_link_libraries(CMakeLib cmsys
${CMAKE_EXPAT_LIBRARIES} ${CMAKE_ZLIB_LIBRARIES}
- ${CMAKE_TAR_LIBRARIES} ${CMAKE_COMPRESS_LIBRARIES}
+ ${CMAKE_TAR_LIBRARIES}
${CMAKE_CURL_LIBRARIES}
${CMAKE_JSONCPP_LIBRARIES}
${CMAKE_LIBUV_LIBRARIES}
@@ -1060,9 +1084,6 @@ if(CPACK_ENABLE_FREEBSD_PKG AND FREEBSD_PKG_INCLUDE_DIRS AND FREEBSD_PKG_LIBRARI
endif()
if(APPLE)
- add_executable(cmakexbuild cmakexbuild.cxx)
- list(APPEND _tools cmakexbuild)
- target_link_libraries(cmakexbuild CMakeLib)
add_executable(OSXScriptLauncher
CPack/OSXScriptLauncher.cxx)
target_link_libraries(OSXScriptLauncher cmsys)
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 01dedde07..ebdb97a29 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,5 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
-set(CMake_VERSION_MINOR 14)
-set(CMake_VERSION_PATCH 7)
+set(CMake_VERSION_MINOR 15)
+set(CMake_VERSION_PATCH 0)
#set(CMake_VERSION_RC 0)
diff --git a/Source/CMakeVersion.rc.in b/Source/CMakeVersion.rc.in
index 22b4a3639..762d9bb62 100644
--- a/Source/CMakeVersion.rc.in
+++ b/Source/CMakeVersion.rc.in
@@ -1,25 +1,16 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
-#define VER_FILEVERSION @CMake_RCVERSION@
-#define VER_FILEVERSION_STR "@CMake_RCVERSION_STR@\0"
-
-#define VER_PRODUCTVERSION @CMake_RCVERSION@
-#define VER_PRODUCTVERSION_STR "@CMake_RCVERSION_STR@\0"
-
-/* Version-information resource identifier. */
-#define VS_VERSION_INFO 1
-
-VS_VERSION_INFO VERSIONINFO
-FILEVERSION VER_FILEVERSION
-PRODUCTVERSION VER_PRODUCTVERSION
+1 VERSIONINFO
+FILEVERSION @CMake_RCVERSION@
+PRODUCTVERSION @CMake_RCVERSION@
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
- VALUE "FileVersion", VER_FILEVERSION_STR
- VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ VALUE "FileVersion", "@CMake_RCVERSION_STR@\0"
+ VALUE "ProductVersion", "@CMake_RCVERSION_STR@\0"
END
END
diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
index 9102e3e20..c1b6eea9a 100644
--- a/Source/CPack/IFW/cmCPackIFWGenerator.cxx
+++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
@@ -85,8 +85,8 @@ int cmCPackIFWGenerator::PackageFiles()
int retVal = 1;
cmCPackIFWLogger(OUTPUT, "- Generate repository" << std::endl);
bool res = cmSystemTools::RunSingleCommand(
- ifwCmd.c_str(), &output, &output, &retVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ ifwCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
if (!res || retVal) {
cmGeneratedFileStream ofs(ifwTmpFile);
ofs << "# Run command: " << ifwCmd << std::endl
@@ -198,8 +198,8 @@ int cmCPackIFWGenerator::PackageFiles()
int retVal = 1;
cmCPackIFWLogger(OUTPUT, "- Generate package" << std::endl);
bool res = cmSystemTools::RunSingleCommand(
- ifwCmd.c_str(), &output, &output, &retVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ ifwCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
if (!res || retVal) {
cmGeneratedFileStream ofs(ifwTmpFile);
ofs << "# Run command: " << ifwCmd << std::endl
diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.cxx b/Source/CPack/IFW/cmCPackIFWInstaller.cxx
index 01e3ea4a7..a075a17e3 100644
--- a/Source/CPack/IFW/cmCPackIFWInstaller.cxx
+++ b/Source/CPack/IFW/cmCPackIFWInstaller.cxx
@@ -152,6 +152,15 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
}
}
+ // StyleSheet
+ if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_STYLE_SHEET")) {
+ if (cmSystemTools::FileExists(option)) {
+ this->StyleSheet = option;
+ } else {
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_STYLE_SHEET", option);
+ }
+ }
+
// WizardDefaultWidth
if (const char* option =
this->GetOption("CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH")) {
@@ -381,6 +390,14 @@ void cmCPackIFWInstaller::GenerateInstallerFile()
xout.Element("WizardStyle", this->WizardStyle);
}
+ // Stylesheet
+ if (!this->StyleSheet.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(this->StyleSheet);
+ std::string path = this->Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(this->StyleSheet, path);
+ xout.Element("StyleSheet", name);
+ }
+
// WizardDefaultWidth
if (!this->WizardDefaultWidth.empty()) {
xout.Element("WizardDefaultWidth", this->WizardDefaultWidth);
diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.h b/Source/CPack/IFW/cmCPackIFWInstaller.h
index 37ad339af..be51fa5fb 100644
--- a/Source/CPack/IFW/cmCPackIFWInstaller.h
+++ b/Source/CPack/IFW/cmCPackIFWInstaller.h
@@ -72,6 +72,9 @@ public:
/// Wizard style name
std::string WizardStyle;
+ /// Filename for a style sheet
+ std::string StyleSheet;
+
/// Wizard width
std::string WizardDefaultWidth;
diff --git a/Source/CPack/OSXScriptLauncher.cxx b/Source/CPack/OSXScriptLauncher.cxx
index 4966d09f2..00d272c83 100644
--- a/Source/CPack/OSXScriptLauncher.cxx
+++ b/Source/CPack/OSXScriptLauncher.cxx
@@ -73,7 +73,7 @@ int main(int argc, char* argv[])
args.push_back(nullptr);
cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*args.begin());
+ cmsysProcess_SetCommand(cp, args.data());
cmsysProcess_SetWorkingDirectory(cp, scriptDirectory.c_str());
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
cmsysProcess_SetTimeout(cp, 0);
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
index 398ebd399..045d93d87 100644
--- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
@@ -61,9 +61,8 @@ bool cmCPackWIXGenerator::RunWiXCommand(std::string const& command)
std::string output;
int returnValue = 0;
- bool status = cmSystemTools::RunSingleCommand(command.c_str(), &output,
- &output, &returnValue, 0,
- cmSystemTools::OUTPUT_NONE);
+ bool status = cmSystemTools::RunSingleCommand(
+ command, &output, &output, &returnValue, 0, cmSystemTools::OUTPUT_NONE);
cmsys::ofstream logFile(logFileName.c_str(), std::ios::app);
logFile << command << std::endl;
@@ -619,7 +618,7 @@ bool cmCPackWIXGenerator::GenerateMainSourceFileFromTemplate()
std::string mainSourceFilePath = this->CPackTopLevel + "/main.wxs";
- if (!ConfigureFile(wixTemplate.c_str(), mainSourceFilePath.c_str())) {
+ if (!ConfigureFile(wixTemplate, mainSourceFilePath)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Failed creating '" << mainSourceFilePath
<< "'' from template." << std::endl);
diff --git a/Source/CPack/bills-comments.txt b/Source/CPack/bills-comments.txt
deleted file mode 100644
index 1aaf9af51..000000000
--- a/Source/CPack/bills-comments.txt
+++ /dev/null
@@ -1,68 +0,0 @@
-cpack.cxx
-
-cmCPackGenerators -- creates cmCPackGenericGenerator's via NewGenerator
- - a cmCPackGenericGenerator factory
-
-
-cmCPackGenericGenerator::Initialize
- this->InitializeInternal
- CPACK_INCLUDE_TOPLEVEL_DIRECTORY = 0 turns off
-
-
-// binary package run
-cmCPackGenericGenerator::ProcessGenerator // DoPackage
- cmCPackGenericGenerator::PrepareNames -- sets a bunch of CPACK_vars
- cmCPackGenericGenerator::InstallProject
- run preinstall (make preinstall/fast)
- call ReadListFile(cmake_install.cmake)
- glob recurse in install directory to get list of files
- this->CompressFiles with the list of files
-
-
-// source package run
-cmCPackGenericGenerator::ProcessGenerator // DoPackage
- cmCPackGenericGenerator::PrepareNames -- sets a bunch of CPACK_vars
- cmCPackGenericGenerator::InstallProject -->
- if set CPACK_INSTALLED_DIRECTORIES
- glob the files in that directory
- copy those files to the tmp install directory _CPack something
- glob recurse in install directory to get list of files
- this->CompressFiles with the list of files
-
-
-cmCPackGenericGenerator::InstallProject is used for both source and binary
-packages. It is controlled based on values set in CPACK_ variables.
-
-
-InstallProject
- 1. CPACK_INSTALL_COMMANDS - a list of commands used to install the package
-
- 2. CPACK_INSTALLED_DIRECTORIES - copy this directory to CPACK_TEMPORARY_DIRECTORY
-
- 3. CPACK_INSTALL_CMAKE_PROJECTS - a cmake install script
- - run make preinstall
- - run cmake_install.cmake
- - set CMAKE_INSTALL_PREFIX to the temp directory
- - CPACK_BUILD_CONFIG check this and set the BUILD_TYPE to it
- - ReadListFile on the install script cmake_install.cmake
- - run strip on the executables and libraries if CPACK_STRIP_FILES is TRUE
-
-Recommendations:
-
-rename cmCPackGenerators to cmCPackGeneratorFactory
-
-rename cmCPackGenericGenerator --> cmCPackGenerator
-
-rename cmCPackGenericGenerator::ProcessGenerator -> cmCPackGenerator::DoPackage
-
-
-break up cmCPackGenerator::InstallProject so it calls the following:
-
-// run user provided install commands
- cmCPackGenerator::RunInstallCommands();
-// copy entire directories that need no processing like source trees
- cmCPackGenerator::CopyPreInstalledDirectories();
-// run the cmake install scripts if provided
- cmCPackGenerator::RunCMakeInstallScripts()
-
--
diff --git a/Source/CPack/cmCPackCygwinBinaryGenerator.cxx b/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
index 2119f782b..49a9f15c3 100644
--- a/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
+++ b/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
@@ -44,10 +44,9 @@ int cmCPackCygwinBinaryGenerator::PackageFiles()
// to create the file before the super class is called
{
cmGeneratedFileStream ofs(manifestFile.c_str());
- for (std::vector<std::string>::const_iterator i = files.begin();
- i != files.end(); ++i) {
+ for (std::string const& file : files) {
// remove the temp dir and replace with /usr
- ofs << (*i).substr(tempdir.size()) << "\n";
+ ofs << file.substr(tempdir.size()) << "\n";
}
ofs << manifest << "\n";
}
diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx
index 635de490a..cfb5efd0e 100644
--- a/Source/CPack/cmCPackDebGenerator.cxx
+++ b/Source/CPack/cmCPackDebGenerator.cxx
@@ -195,7 +195,7 @@ bool DebGenerator::generateDataTar() const
// XXX/application/usr/bin/myprogram with GEN_WDIR=XXX/application
// should not add XXX/application
orderedFiles.insert(currentPath);
- currentPath = cmSystemTools::CollapseCombinedPath(currentPath, "..");
+ currentPath = cmSystemTools::CollapseFullPath("..", currentPath);
}
}
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
index 013ad8163..7a3742b55 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.cxx
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -244,8 +244,8 @@ bool cmCPackDragNDropGenerator::RunCommand(std::ostringstream& command,
int exit_code = 1;
bool result = cmSystemTools::RunSingleCommand(
- command.str().c_str(), output, output, &exit_code, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ command.str(), output, output, &exit_code, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
if (!result || exit_code) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
diff --git a/Source/CPack/cmCPackFreeBSDGenerator.cxx b/Source/CPack/cmCPackFreeBSDGenerator.cxx
index fcf8af1f8..9fdafa47b 100644
--- a/Source/CPack/cmCPackFreeBSDGenerator.cxx
+++ b/Source/CPack/cmCPackFreeBSDGenerator.cxx
@@ -181,7 +181,7 @@ public:
{
s << "{\n";
for (std::string const& elem : value) {
- s << " \"" << elem << "\": {\"origin\": \"" << elem << "\"},\n";
+ s << " \"" << elem << R"(": {"origin": ")" << elem << "\"},\n";
}
s << '}';
}
@@ -325,8 +325,7 @@ int cmCPackFreeBSDGenerator::PackageFiles()
ONE_PACKAGE_PER_COMPONENT);
}
- std::string output_dir =
- cmSystemTools::CollapseCombinedPath(toplevel, "../");
+ std::string output_dir = cmSystemTools::CollapseFullPath("../", toplevel);
pkg_create_from_manifest(output_dir.c_str(), ::TXZ, toplevel.c_str(),
manifestname.c_str(), nullptr);
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index 57c054590..7e07ff488 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -15,6 +15,7 @@
#include "cmCryptoHash.h"
#include "cmDuration.h"
#include "cmFSPermissions.h"
+#include "cmFileTimes.h"
#include "cmGeneratedFileStream.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
@@ -43,7 +44,8 @@ cmCPackGenerator::~cmCPackGenerator()
this->MakefileMap = nullptr;
}
-void cmCPackGenerator::DisplayVerboseOutput(const char* msg, float progress)
+void cmCPackGenerator::DisplayVerboseOutput(const std::string& msg,
+ float progress)
{
(void)progress;
cmCPackLogger(cmCPackLog::LOG_VERBOSE, "" << msg << std::endl);
@@ -278,7 +280,7 @@ int cmCPackGenerator::InstallProjectViaInstallCommands(
std::string output;
int retVal = 1;
bool resB = cmSystemTools::RunSingleCommand(
- ic.c_str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ ic, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
cmDuration::zero());
if (!resB || retVal) {
std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
@@ -387,8 +389,7 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories(
}
/* If it is not a symlink then do a plain copy */
else if (!(cmSystemTools::CopyFileIfDifferent(inFile, filePath) &&
- cmSystemTools::CopyFileTime(inFile.c_str(),
- filePath.c_str()))) {
+ cmFileTimes::Copy(inFile, filePath))) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem copying file: " << inFile << " -> "
<< filePath << std::endl);
@@ -647,8 +648,8 @@ int cmCPackGenerator::RunPreinstallTarget(
std::string output;
int retVal = 1;
bool resB = cmSystemTools::RunSingleCommand(
- buildCommand.c_str(), &output, &output, &retVal,
- installDirectory.c_str(), this->GeneratorVerbose, cmDuration::zero());
+ buildCommand, &output, &output, &retVal, installDirectory.c_str(),
+ this->GeneratorVerbose, cmDuration::zero());
if (!resB || retVal) {
std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
tmpFile += "/PreinstallOutput.log";
@@ -689,7 +690,7 @@ int cmCPackGenerator::InstallCMakeProject(
cm.SetHomeOutputDirectory("");
cm.GetCurrentSnapshot().SetDefaultDefinitions();
cm.AddCMakePaths();
- cm.SetProgressCallback([this](const char* msg, float prog) {
+ cm.SetProgressCallback([this](const std::string& msg, float prog) {
this->DisplayVerboseOutput(msg, prog);
});
cm.SetTrace(this->Trace);
@@ -1245,7 +1246,8 @@ bool cmCPackGenerator::ConfigureString(const std::string& inString,
return true;
}
-bool cmCPackGenerator::ConfigureFile(const char* inName, const char* outName,
+bool cmCPackGenerator::ConfigureFile(const std::string& inName,
+ const std::string& outName,
bool copyOnly /* = false */)
{
return this->MakefileMap->ConfigureFile(inName, outName, copyOnly, true,
@@ -1254,9 +1256,8 @@ bool cmCPackGenerator::ConfigureFile(const char* inName, const char* outName,
int cmCPackGenerator::CleanTemporaryDirectory()
{
- std::string tempInstallDirectoryWithPostfix =
+ std::string tempInstallDirectory =
this->GetOption("CPACK_TEMPORARY_INSTALL_DIRECTORY");
- const char* tempInstallDirectory = tempInstallDirectoryWithPostfix.c_str();
if (cmsys::SystemTools::FileExists(tempInstallDirectory)) {
cmCPackLogger(cmCPackLog::LOG_OUTPUT,
"- Clean temporary : " << tempInstallDirectory << std::endl);
diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h
index 4755f942b..3c06d4196 100644
--- a/Source/CPack/cmCPackGenerator.h
+++ b/Source/CPack/cmCPackGenerator.h
@@ -96,7 +96,7 @@ public:
void SetLogger(cmCPackLog* log) { this->Logger = log; }
//! Display verbose information via logger
- void DisplayVerboseOutput(const char* msg, float progress);
+ void DisplayVerboseOutput(const std::string& msg, float progress);
bool ReadListFile(const char* moduleName);
@@ -169,7 +169,8 @@ protected:
virtual const char* GetPackagingInstallPrefix();
virtual std::string FindTemplate(const char* name);
- virtual bool ConfigureFile(const char* inName, const char* outName,
+ virtual bool ConfigureFile(const std::string& inName,
+ const std::string& outName,
bool copyOnly = false);
virtual bool ConfigureString(const std::string& input, std::string& output);
virtual int InitializeInternal();
diff --git a/Source/CPack/cmCPackGeneratorFactory.h b/Source/CPack/cmCPackGeneratorFactory.h
index 7f633e473..972f0f73c 100644
--- a/Source/CPack/cmCPackGeneratorFactory.h
+++ b/Source/CPack/cmCPackGeneratorFactory.h
@@ -22,6 +22,9 @@ public:
cmCPackGeneratorFactory();
~cmCPackGeneratorFactory();
+ cmCPackGeneratorFactory(const cmCPackGeneratorFactory&) = delete;
+ cmCPackGeneratorFactory& operator=(const cmCPackGeneratorFactory&) = delete;
+
//! Get the generator
cmCPackGenerator* NewGenerator(const std::string& name);
void DeleteGenerator(cmCPackGenerator* gen);
diff --git a/Source/CPack/cmCPackLog.h b/Source/CPack/cmCPackLog.h
index 8e9922121..65281e3d8 100644
--- a/Source/CPack/cmCPackLog.h
+++ b/Source/CPack/cmCPackLog.h
@@ -26,6 +26,9 @@ public:
cmCPackLog();
~cmCPackLog();
+ cmCPackLog(const cmCPackLog&) = delete;
+ cmCPackLog& operator=(const cmCPackLog&) = delete;
+
enum __log_tags
{
NOTAG = 0,
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
index 37ea66e76..e2020c5ae 100644
--- a/Source/CPack/cmCPackNSISGenerator.cxx
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -182,7 +182,7 @@ int cmCPackNSISGenerator::PackageFiles()
this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC", "");
this->SetOptionIfNotSet("CPACK_NSIS_PAGE_COMPONENTS", "");
this->SetOptionIfNotSet("CPACK_NSIS_FULL_INSTALL",
- "File /r \"${INST_DIR}\\*.*\"");
+ R"(File /r "${INST_DIR}\*.*")");
this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTIONS", "");
this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTION_LIST", "");
this->SetOptionIfNotSet("CPACK_NSIS_SECTION_SELECTED_VARS", "");
@@ -242,7 +242,7 @@ int cmCPackNSISGenerator::PackageFiles()
}
// Add this component to the various section lists.
- sectionList += " !insertmacro \"${MacroName}\" \"";
+ sectionList += R"( !insertmacro "${MacroName}" ")";
sectionList += comp.first;
sectionList += "\"\n";
selectedVarsList += "Var " + comp.first + "_selected\n";
@@ -292,9 +292,8 @@ int cmCPackNSISGenerator::PackageFiles()
this->SetOption("CPACK_NSIS_DEFINES", defines.c_str());
}
- this->ConfigureFile(nsisInInstallOptions.c_str(),
- nsisInstallOptions.c_str());
- this->ConfigureFile(nsisInFileName.c_str(), nsisFileName.c_str());
+ this->ConfigureFile(nsisInInstallOptions, nsisInstallOptions);
+ this->ConfigureFile(nsisInFileName, nsisFileName);
std::string nsisCmd = "\"";
nsisCmd += this->GetOption("CPACK_INSTALLER_PROGRAM");
nsisCmd += "\" \"" + nsisFileName + "\"";
@@ -302,8 +301,8 @@ int cmCPackNSISGenerator::PackageFiles()
std::string output;
int retVal = 1;
bool res = cmSystemTools::RunSingleCommand(
- nsisCmd.c_str(), &output, &output, &retVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ nsisCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
if (!res || retVal) {
cmGeneratedFileStream ofs(tmpFile);
ofs << "# Run command: " << nsisCmd << std::endl
@@ -407,8 +406,8 @@ int cmCPackNSISGenerator::InitializeInternal()
std::string output;
int retVal = 1;
bool resS = cmSystemTools::RunSingleCommand(
- nsisCmd.c_str(), &output, &output, &retVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ nsisCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
cmsys::RegularExpression versionRex("v([0-9]+.[0-9]+)");
cmsys::RegularExpression versionRexCVS("v(.*)\\.cvs");
if (!resS || retVal ||
@@ -495,10 +494,10 @@ int cmCPackNSISGenerator::InitializeInternal()
std::string execName = *it;
++it;
std::string linkName = *it;
- str << " CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
- << ".lnk\" \"$INSTDIR\\" << cpackNsisExecutablesDirectory << "\\"
+ str << R"( CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\)" << linkName
+ << R"(.lnk" "$INSTDIR\)" << cpackNsisExecutablesDirectory << "\\"
<< execName << ".exe\"" << std::endl;
- deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+ deleteStr << R"( Delete "$SMPROGRAMS\$MUI_TEMP\)" << linkName
<< ".lnk\"" << std::endl;
// see if CPACK_CREATE_DESKTOP_LINK_ExeName is on
// if so add a desktop link
@@ -508,7 +507,7 @@ int cmCPackNSISGenerator::InitializeInternal()
execName) != cpackPackageDesktopLinksVector.end()) {
str << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
str << " CreateShortCut \"$DESKTOP\\" << linkName
- << ".lnk\" \"$INSTDIR\\" << cpackNsisExecutablesDirectory << "\\"
+ << R"(.lnk" "$INSTDIR\)" << cpackNsisExecutablesDirectory << "\\"
<< execName << ".exe\"" << std::endl;
deleteStr << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
deleteStr << " Delete \"$DESKTOP\\" << linkName << ".lnk\""
@@ -564,15 +563,15 @@ void cmCPackNSISGenerator::CreateMenuLinks(std::ostream& str,
++it;
std::string linkName = *it;
if (!url) {
- str << " CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
- << ".lnk\" \"$INSTDIR\\" << sourceName << "\"" << std::endl;
- deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+ str << R"( CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\)" << linkName
+ << R"(.lnk" "$INSTDIR\)" << sourceName << "\"" << std::endl;
+ deleteStr << R"( Delete "$SMPROGRAMS\$MUI_TEMP\)" << linkName
<< ".lnk\"" << std::endl;
} else {
- str << " WriteINIStr \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
- << ".url\" \"InternetShortcut\" \"URL\" \"" << sourceName << "\""
+ str << R"( WriteINIStr "$SMPROGRAMS\$STARTMENU_FOLDER\)" << linkName
+ << R"(.url" "InternetShortcut" "URL" ")" << sourceName << "\""
<< std::endl;
- deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+ deleteStr << R"( Delete "$SMPROGRAMS\$MUI_TEMP\)" << linkName
<< ".url\"" << std::endl;
}
// see if CPACK_CREATE_DESKTOP_LINK_ExeName is on
@@ -582,7 +581,7 @@ void cmCPackNSISGenerator::CreateMenuLinks(std::ostream& str,
if (this->IsSet(desktop)) {
str << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
str << " CreateShortCut \"$DESKTOP\\" << linkName
- << ".lnk\" \"$INSTDIR\\" << sourceName << "\"" << std::endl;
+ << R"(.lnk" "$INSTDIR\)" << sourceName << "\"" << std::endl;
deleteStr << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
deleteStr << " Delete \"$DESKTOP\\" << linkName << ".lnk\""
<< std::endl;
@@ -749,7 +748,7 @@ std::string cmCPackNSISGenerator::CreateComponentDescription(
std::string output;
int retVal = -1;
int res = cmSystemTools::RunSingleCommand(
- cmd.c_str(), &output, &output, &retVal, dirName.c_str(),
+ cmd, &output, &output, &retVal, dirName.c_str(),
cmSystemTools::OUTPUT_NONE, cmDuration::zero());
if (!res || retVal) {
std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
diff --git a/Source/CPack/cmCPackOSXX11Generator.cxx b/Source/CPack/cmCPackOSXX11Generator.cxx
index 486633c90..90e0afe7f 100644
--- a/Source/CPack/cmCPackOSXX11Generator.cxx
+++ b/Source/CPack/cmCPackOSXX11Generator.cxx
@@ -83,7 +83,7 @@ int cmCPackOSXX11Generator::PackageFiles()
return 0;
}
std::string destFileName = resourcesDirectory + "/" + iconFileName;
- this->ConfigureFile(iconFile, destFileName.c_str(), true);
+ this->ConfigureFile(iconFile, destFileName, true);
this->SetOptionIfNotSet("CPACK_APPLE_GUI_ICON", iconFileName.c_str());
}
@@ -155,8 +155,8 @@ int cmCPackOSXX11Generator::PackageFiles()
bool res = false;
while (numTries > 0) {
res = cmSystemTools::RunSingleCommand(
- dmgCmd.str().c_str(), &output, &output, &retVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ dmgCmd.str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
if (res && !retVal) {
numTries = -1;
break;
@@ -236,7 +236,7 @@ bool cmCPackOSXX11Generator::CopyCreateResourceFile(const std::string& name)
cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
<< (inFileName ? inFileName : "(NULL)")
<< " to " << destFileName << std::endl);
- this->ConfigureFile(inFileName, destFileName.c_str());
+ this->ConfigureFile(inFileName, destFileName);
return true;
}
*/
@@ -266,7 +266,7 @@ bool cmCPackOSXX11Generator::CopyResourcePlistFile(
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
"Configure file: " << inFileName << " to " << destFileName
<< std::endl);
- this->ConfigureFile(inFileName.c_str(), destFileName.c_str(), copyOnly);
+ this->ConfigureFile(inFileName, destFileName, copyOnly);
return true;
}
diff --git a/Source/CPack/cmCPackPKGGenerator.cxx b/Source/CPack/cmCPackPKGGenerator.cxx
index ae227aab1..8c22c65b0 100644
--- a/Source/CPack/cmCPackPKGGenerator.cxx
+++ b/Source/CPack/cmCPackPKGGenerator.cxx
@@ -66,21 +66,17 @@ void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile)
xout.StartElement("choices-outline");
// Emit the outline for the groups
- std::map<std::string, cmCPackComponentGroup>::iterator groupIt;
- for (groupIt = this->ComponentGroups.begin();
- groupIt != this->ComponentGroups.end(); ++groupIt) {
- if (groupIt->second.ParentGroup == nullptr) {
- CreateChoiceOutline(groupIt->second, xout);
+ for (auto const& group : this->ComponentGroups) {
+ if (group.second.ParentGroup == nullptr) {
+ CreateChoiceOutline(group.second, xout);
}
}
// Emit the outline for the non-grouped components
- std::map<std::string, cmCPackComponent>::iterator compIt;
- for (compIt = this->Components.begin(); compIt != this->Components.end();
- ++compIt) {
- if (!compIt->second.Group) {
+ for (auto const& comp : this->Components) {
+ if (!comp.second.Group) {
xout.StartElement("line");
- xout.Attribute("choice", compIt->first + "Choice");
+ xout.Attribute("choice", comp.first + "Choice");
xout.Content(""); // Avoid self-closing tag.
xout.EndElement();
}
@@ -94,13 +90,11 @@ void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile)
xout.EndElement(); // choices-outline>
// Create the actual choices
- for (groupIt = this->ComponentGroups.begin();
- groupIt != this->ComponentGroups.end(); ++groupIt) {
- CreateChoice(groupIt->second, xout);
+ for (auto const& group : this->ComponentGroups) {
+ CreateChoice(group.second, xout);
}
- for (compIt = this->Components.begin(); compIt != this->Components.end();
- ++compIt) {
- CreateChoice(compIt->second, xout);
+ for (auto const& comp : this->Components) {
+ CreateChoice(comp.second, xout);
}
if (!this->PostFlightComponent.Name.empty()) {
@@ -111,7 +105,7 @@ void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile)
// Create the distribution.dist file in the metapackage to turn it
// into a distribution package.
- this->ConfigureFile(distributionTemplate.c_str(), distributionFile.c_str());
+ this->ConfigureFile(distributionTemplate, distributionFile);
}
void cmCPackPKGGenerator::CreateChoiceOutline(
@@ -119,17 +113,13 @@ void cmCPackPKGGenerator::CreateChoiceOutline(
{
xout.StartElement("line");
xout.Attribute("choice", group.Name + "Choice");
- std::vector<cmCPackComponentGroup*>::const_iterator groupIt;
- for (groupIt = group.Subgroups.begin(); groupIt != group.Subgroups.end();
- ++groupIt) {
- CreateChoiceOutline(**groupIt, xout);
+ for (cmCPackComponentGroup* subgroup : group.Subgroups) {
+ CreateChoiceOutline(*subgroup, xout);
}
- std::vector<cmCPackComponent*>::const_iterator compIt;
- for (compIt = group.Components.begin(); compIt != group.Components.end();
- ++compIt) {
+ for (cmCPackComponent* comp : group.Components) {
xout.StartElement("line");
- xout.Attribute("choice", (*compIt)->Name + "Choice");
+ xout.Attribute("choice", comp->Name + "Choice");
xout.Content(""); // Avoid self-closing tag.
xout.EndElement();
}
@@ -238,11 +228,9 @@ void cmCPackPKGGenerator::AddDependencyAttributes(
}
visited.insert(&component);
- std::vector<cmCPackComponent*>::const_iterator dependIt;
- for (dependIt = component.Dependencies.begin();
- dependIt != component.Dependencies.end(); ++dependIt) {
- out << " && choices['" << (*dependIt)->Name << "Choice'].selected";
- AddDependencyAttributes(**dependIt, visited, out);
+ for (cmCPackComponent* depend : component.Dependencies) {
+ out << " && choices['" << depend->Name << "Choice'].selected";
+ AddDependencyAttributes(*depend, visited, out);
}
}
@@ -255,11 +243,9 @@ void cmCPackPKGGenerator::AddReverseDependencyAttributes(
}
visited.insert(&component);
- std::vector<cmCPackComponent*>::const_iterator dependIt;
- for (dependIt = component.ReverseDependencies.begin();
- dependIt != component.ReverseDependencies.end(); ++dependIt) {
- out << " || choices['" << (*dependIt)->Name << "Choice'].selected";
- AddReverseDependencyAttributes(**dependIt, visited, out);
+ for (cmCPackComponent* depend : component.ReverseDependencies) {
+ out << " || choices['" << depend->Name << "Choice'].selected";
+ AddReverseDependencyAttributes(*depend, visited, out);
}
}
@@ -308,7 +294,7 @@ bool cmCPackPKGGenerator::CopyCreateResourceFile(const std::string& name,
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
"Configure file: " << (inFileName ? inFileName : "(NULL)")
<< " to " << destFileName << std::endl);
- this->ConfigureFile(inFileName, destFileName.c_str());
+ this->ConfigureFile(inFileName, destFileName);
return true;
}
@@ -336,7 +322,7 @@ bool cmCPackPKGGenerator::CopyResourcePlistFile(const std::string& name,
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
"Configure file: " << inFileName << " to " << destFileName
<< std::endl);
- this->ConfigureFile(inFileName.c_str(), destFileName.c_str());
+ this->ConfigureFile(inFileName, destFileName);
return true;
}
diff --git a/Source/CPack/cmCPackPackageMakerGenerator.cxx b/Source/CPack/cmCPackPackageMakerGenerator.cxx
index 246178d8f..3d93c48f1 100644
--- a/Source/CPack/cmCPackPackageMakerGenerator.cxx
+++ b/Source/CPack/cmCPackPackageMakerGenerator.cxx
@@ -295,8 +295,8 @@ int cmCPackPackageMakerGenerator::PackageFiles()
bool res = false;
while (numTries > 0) {
res = cmSystemTools::RunSingleCommand(
- dmgCmd.str().c_str(), &output, &output, &retVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ dmgCmd.str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
if (res && !retVal) {
numTries = -1;
break;
diff --git a/Source/CPack/cmCPackProductBuildGenerator.cxx b/Source/CPack/cmCPackProductBuildGenerator.cxx
index a556e0c52..94b5b5f7e 100644
--- a/Source/CPack/cmCPackProductBuildGenerator.cxx
+++ b/Source/CPack/cmCPackProductBuildGenerator.cxx
@@ -145,8 +145,8 @@ bool cmCPackProductBuildGenerator::RunProductBuild(const std::string& command)
std::string output;
int retVal = 1;
bool res = cmSystemTools::RunSingleCommand(
- command.c_str(), &output, &output, &retVal, nullptr,
- this->GeneratorVerbose, cmDuration::zero());
+ command, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
+ cmDuration::zero());
cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running command" << std::endl);
if (!res || retVal) {
cmGeneratedFileStream ofs(tmpFile);
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index 0413422b2..58b9e70fa 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -82,7 +82,7 @@ int cpackDefinitionArgument(const char* argument, const char* cValue,
return 0;
}
std::string key = value.substr(0, pos);
- value = value.c_str() + pos + 1;
+ value = value.substr(pos + 1);
def->Map[key] = value;
cmCPack_Log(def->Log, cmCPackLog::LOG_DEBUG,
"Set CPack variable: " << key << " to \"" << value << "\""
@@ -90,7 +90,7 @@ int cpackDefinitionArgument(const char* argument, const char* cValue,
return 1;
}
-static void cpackProgressCallback(const char* message, float /*unused*/)
+static void cpackProgressCallback(const std::string& message, float /*unused*/)
{
std::cout << "-- " << message << std::endl;
}
@@ -98,6 +98,7 @@ static void cpackProgressCallback(const char* message, float /*unused*/)
// this is CPack.
int main(int argc, char const* const* argv)
{
+ cmSystemTools::EnsureStdPipes();
#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
// Replace streambuf so we can output Unicode to console
cmsys::ConsoleBuf::Manager consoleOut(std::cout);
diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx
index b154caf30..b957856e8 100644
--- a/Source/CTest/cmCTestBZR.cxx
+++ b/Source/CTest/cmCTestBZR.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestBZR.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCTestVC.h"
#include "cmProcessTools.h"
@@ -242,7 +243,7 @@ private:
void CharacterDataHandler(const char* data, int length) override
{
- this->CData.insert(this->CData.end(), data, data + length);
+ cmAppend(this->CData, data, data + length);
}
void EndElement(const std::string& name) override
@@ -365,7 +366,7 @@ bool cmCTestBZR::UpdateImpl()
if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("BZRUpdateOptions");
}
- std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
// TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index 2fd4c7ab3..9ad96699b 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -118,7 +118,7 @@ public:
: CM(cm)
{
cmSystemTools::SetMessageCallback(
- [&s](const char* msg, const char* /*unused*/) {
+ [&s](const std::string& msg, const char* /*unused*/) {
s += msg;
s += "\n";
});
@@ -126,9 +126,11 @@ public:
cmSystemTools::SetStdoutCallback([&s](std::string const& m) { s += m; });
cmSystemTools::SetStderrCallback([&s](std::string const& m) { s += m; });
- this->CM.SetProgressCallback([&s](const char* msg, float /*unused*/) {
- s += msg;
- s += "\n";
+ this->CM.SetProgressCallback([&s](const std::string& msg, float prog) {
+ if (prog < 0) {
+ s += msg;
+ s += "\n";
+ }
});
}
@@ -139,6 +141,11 @@ public:
cmSystemTools::SetStdoutCallback(nullptr);
cmSystemTools::SetMessageCallback(nullptr);
}
+
+ cmCTestBuildAndTestCaptureRAII(const cmCTestBuildAndTestCaptureRAII&) =
+ delete;
+ cmCTestBuildAndTestCaptureRAII& operator=(
+ const cmCTestBuildAndTestCaptureRAII&) = delete;
};
int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
@@ -250,7 +257,7 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
}
int retVal = cm.GetGlobalGenerator()->Build(
cmake::NO_BUILD_PARALLEL_LEVEL, this->SourceDir, this->BinaryDir,
- this->BuildProject, tar, output, this->BuildMakeProgram, config,
+ this->BuildProject, { tar }, output, this->BuildMakeProgram, config,
!this->BuildNoClean, false, false, remainingTime);
out << output;
// if the build failed then return
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.h b/Source/CTest/cmCTestBuildAndTestHandler.h
index 5e6d0aad2..2d47b1580 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.h
+++ b/Source/CTest/cmCTestBuildAndTestHandler.h
@@ -44,7 +44,7 @@ public:
void Initialize() override;
protected:
- ///! Run CMake and build a test and then run it as a single test.
+ //! Run CMake and build a test and then run it as a single test.
int RunCMakeAndTest(std::string* output);
int RunCMake(std::string* outstring, std::ostringstream& out,
std::string& cmakeOutString, cmake* cm);
diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx
index 32f7496a9..2eacaf144 100644
--- a/Source/CTest/cmCTestBuildCommand.cxx
+++ b/Source/CTest/cmCTestBuildCommand.cxx
@@ -4,7 +4,6 @@
#include "cmCTest.h"
#include "cmCTestBuildHandler.h"
-#include "cmCTestGenericHandler.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
@@ -39,12 +38,10 @@ cmCTestBuildCommand::~cmCTestBuildCommand()
cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
{
- cmCTestGenericHandler* handler = this->CTest->GetInitializedHandler("build");
- if (!handler) {
- this->SetError("internal CTest error. Cannot instantiate build handler");
- return nullptr;
- }
- this->Handler = static_cast<cmCTestBuildHandler*>(handler);
+ cmCTestBuildHandler* handler = this->CTest->GetBuildHandler();
+ handler->Initialize();
+
+ this->Handler = handler;
const char* ctestBuildCommand =
this->Makefile->GetDefinition("CTEST_BUILD_COMMAND");
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index d934c003c..c8e4fa1b4 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -5,7 +5,7 @@
#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmDuration.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTimeCache.h"
#include "cmGeneratedFileStream.h"
#include "cmMakefile.h"
#include "cmProcessOutput.h"
@@ -32,13 +32,13 @@ static const char* cmCTestErrorMatches[] = {
"^Error: ",
"^Error ",
"[0-9] ERROR: ",
- "^\"[^\"]+\", line [0-9]+: [^Ww]",
+ R"(^"[^"]+", line [0-9]+: [^Ww])",
"^cc[^C]*CC: ERROR File = ([^,]+), Line = ([0-9]+)",
"^ld([^:])*:([ \\t])*ERROR([^:])*:",
- "^ild:([ \\t])*\\(undefined symbol\\)",
+ R"(^ild:([ \t])*\(undefined symbol\))",
"([^ :]+) : (error|fatal error|catastrophic error)",
"([^:]+): (Error:|error|undefined reference|multiply defined)",
- "([^:]+)\\(([^\\)]+)\\) ?: (error|fatal error|catastrophic error)",
+ R"(([^:]+)\(([^\)]+)\) ?: (error|fatal error|catastrophic error))",
"^fatal error C[0-9]+:",
": syntax error ",
"^collect2: ld returned 1 exit status",
@@ -50,14 +50,14 @@ static const char* cmCTestErrorMatches[] = {
"^CMake Error.*:",
":[ \\t]cannot find",
":[ \\t]can't find",
- ": \\*\\*\\* No rule to make target [`'].*\\'. Stop",
- ": \\*\\*\\* No targets specified and no makefile found",
+ R"(: \*\*\* No rule to make target [`'].*\'. Stop)",
+ R"(: \*\*\* No targets specified and no makefile found)",
": Invalid loader fixup for symbol",
": Invalid fixups exist",
": Can't find library for",
": internal link edit command failed",
": Unrecognized option [`'].*\\'",
- "\", line [0-9]+\\.[0-9]+: [0-9]+-[0-9]+ \\([^WI]\\)",
+ R"(", line [0-9]+\.[0-9]+: [0-9]+-[0-9]+ \([^WI]\))",
"ld: 0706-006 Cannot find or open library file: -l ",
"ild: \\(argument error\\) can't find library argument ::",
"^could not be found and will not be loaded.",
@@ -66,11 +66,11 @@ static const char* cmCTestErrorMatches[] = {
"ld: 0711-993 Error occurred while writing to the output file:",
"ld: fatal: ",
"final link failed:",
- "make: \\*\\*\\*.*Error",
- "make\\[.*\\]: \\*\\*\\*.*Error",
- "\\*\\*\\* Error code",
+ R"(make: \*\*\*.*Error)",
+ R"(make\[.*\]: \*\*\*.*Error)",
+ R"(\*\*\* Error code)",
"nternal error:",
- "Makefile:[0-9]+: \\*\\*\\* .* Stop\\.",
+ R"(Makefile:[0-9]+: \*\*\* .* Stop\.)",
": No such file or directory",
": Invalid argument",
"^The project cannot be built\\.",
@@ -101,19 +101,19 @@ static const char* cmCTestWarningMatches[] = {
"^cc[^C]*CC: WARNING File = ([^,]+), Line = ([0-9]+)",
"^ld([^:])*:([ \\t])*WARNING([^:])*:",
"([^:]+): warning ([0-9]+):",
- "^\"[^\"]+\", line [0-9]+: [Ww](arning|arnung)",
+ R"(^"[^"]+", line [0-9]+: [Ww](arning|arnung))",
"([^:]+): warning[ \\t]*[0-9]+[ \\t]*:",
"^(Warning|Warnung) ([0-9]+):",
"^(Warning|Warnung)[ :]",
"WARNING: ",
"([^ :]+) : warning",
"([^:]+): warning",
- "\", line [0-9]+\\.[0-9]+: [0-9]+-[0-9]+ \\([WI]\\)",
+ R"(", line [0-9]+\.[0-9]+: [0-9]+-[0-9]+ \([WI]\))",
"^cxx: Warning:",
".*file: .* has no symbols",
"([^ :]+):([0-9]+): (Warning|Warnung)",
"\\([0-9]*\\): remark #[0-9]*",
- "\".*\", line [0-9]+: remark\\([0-9]*\\):",
+ R"(".*", line [0-9]+: remark\([0-9]*\):)",
"cc-[0-9]* CC: REMARK File = .*, Line = [0-9]*",
"^CMake Warning.*:",
"^\\[WARNING\\]",
@@ -121,9 +121,9 @@ static const char* cmCTestWarningMatches[] = {
};
static const char* cmCTestWarningExceptions[] = {
- "/usr/.*/X11/Xlib\\.h:[0-9]+: war.*: ANSI C\\+\\+ forbids declaration",
- "/usr/.*/X11/Xutil\\.h:[0-9]+: war.*: ANSI C\\+\\+ forbids declaration",
- "/usr/.*/X11/XResource\\.h:[0-9]+: war.*: ANSI C\\+\\+ forbids declaration",
+ R"(/usr/.*/X11/Xlib\.h:[0-9]+: war.*: ANSI C\+\+ forbids declaration)",
+ R"(/usr/.*/X11/Xutil\.h:[0-9]+: war.*: ANSI C\+\+ forbids declaration)",
+ R"(/usr/.*/X11/XResource\.h:[0-9]+: war.*: ANSI C\+\+ forbids declaration)",
"WARNING 84 :",
"WARNING 47 :",
"makefile:",
@@ -150,8 +150,8 @@ struct cmCTestBuildCompileErrorWarningRex
static cmCTestBuildCompileErrorWarningRex cmCTestWarningErrorFileLine[] = {
{ "^Warning W[0-9]+ ([a-zA-Z.\\:/0-9_+ ~-]+) ([0-9]+):", 1, 2 },
{ "^([a-zA-Z./0-9_+ ~-]+):([0-9]+):", 1, 2 },
- { "^([a-zA-Z.\\:/0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
- { "^[0-9]+>([a-zA-Z.\\:/0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
+ { R"(^([a-zA-Z.\:/0-9_+ ~-]+)\(([0-9]+)\))", 1, 2 },
+ { R"(^[0-9]+>([a-zA-Z.\:/0-9_+ ~-]+)\(([0-9]+)\))", 1, 2 },
{ "^([a-zA-Z./0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 },
{ "\"([a-zA-Z./0-9_+ ~-]+)\", line ([0-9]+)", 1, 2 },
{ "File = ([a-zA-Z./0-9_+ ~-]+), Line = ([0-9]+)", 1, 2 },
@@ -387,7 +387,7 @@ int cmCTestBuildHandler::ProcessHandler()
std::string srcdirrep;
for (cc = srcdir.size() - 2; cc > 0; cc--) {
if (srcdir[cc] == '/') {
- srcdirrep = srcdir.c_str() + cc;
+ srcdirrep = srcdir.substr(cc);
srcdirrep = "/..." + srcdirrep;
srcdir = srcdir.substr(0, cc + 1);
break;
@@ -401,7 +401,7 @@ int cmCTestBuildHandler::ProcessHandler()
std::string bindirrep;
for (cc = bindir.size() - 2; cc > 0; cc--) {
if (bindir[cc] == '/') {
- bindirrep = bindir.c_str() + cc;
+ bindirrep = bindir.substr(cc);
bindirrep = "/..." + bindirrep;
bindir = bindir.substr(0, cc + 1);
break;
@@ -418,8 +418,8 @@ int cmCTestBuildHandler::ProcessHandler()
int retVal = 0;
int res = cmsysProcess_State_Exited;
if (!this->CTest->GetShowOnly()) {
- res = this->RunMakeCommand(makeCommand.c_str(), &retVal,
- buildDirectory.c_str(), 0, ofs);
+ res = this->RunMakeCommand(makeCommand, &retVal, buildDirectory.c_str(), 0,
+ ofs);
} else {
cmCTestOptionalLog(this->CTest, DEBUG,
"Build with command: " << makeCommand << std::endl,
@@ -503,7 +503,7 @@ void cmCTestBuildHandler::GenerateXMLHeader(cmXMLWriter& xml)
class cmCTestBuildHandler::FragmentCompare
{
public:
- FragmentCompare(cmFileTimeComparison* ftc)
+ FragmentCompare(cmFileTimeCache* ftc)
: FTC(ftc)
{
}
@@ -513,14 +513,14 @@ public:
// Order files by modification time. Use lexicographic order
// among files with the same time.
int result;
- if (this->FTC->FileTimeCompare(l, r, &result) && result != 0) {
+ if (this->FTC->Compare(l, r, &result) && result != 0) {
return result < 0;
}
return l < r;
}
private:
- cmFileTimeComparison* FTC = nullptr;
+ cmFileTimeCache* FTC = nullptr;
};
void cmCTestBuildHandler::GenerateXMLLaunched(cmXMLWriter& xml)
@@ -530,7 +530,7 @@ void cmCTestBuildHandler::GenerateXMLLaunched(cmXMLWriter& xml)
}
// Sort XML fragments in chronological order.
- cmFileTimeComparison ftc;
+ cmFileTimeCache ftc;
FragmentCompare fragmentCompare(&ftc);
typedef std::set<std::string, FragmentCompare> Fragments;
Fragments fragments(fragmentCompare);
@@ -680,6 +680,8 @@ class cmCTestBuildHandler::LaunchHelper
public:
LaunchHelper(cmCTestBuildHandler* handler);
~LaunchHelper();
+ LaunchHelper(const LaunchHelper&) = delete;
+ LaunchHelper& operator=(const LaunchHelper&) = delete;
private:
cmCTestBuildHandler* Handler;
@@ -764,9 +766,10 @@ void cmCTestBuildHandler::LaunchHelper::WriteScrapeMatchers(
}
}
-int cmCTestBuildHandler::RunMakeCommand(const char* command, int* retVal,
- const char* dir, int timeout,
- std::ostream& ofs, Encoding encoding)
+int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
+ int* retVal, const char* dir,
+ int timeout, std::ostream& ofs,
+ Encoding encoding)
{
// First generate the command and arguments
std::vector<std::string> args = cmSystemTools::ParseArguments(command);
@@ -800,7 +803,7 @@ int cmCTestBuildHandler::RunMakeCommand(const char* command, int* retVal,
// Now create process object
cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetCommand(cp, argv.data());
cmsysProcess_SetWorkingDirectory(cp, dir);
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
cmsysProcess_SetTimeout(cp, timeout);
@@ -975,10 +978,9 @@ void cmCTestBuildHandler::ProcessBuffer(const char* data, size_t length,
if (it != queue->end()) {
// Create a contiguous array for the line
this->CurrentProcessingLine.clear();
- this->CurrentProcessingLine.insert(this->CurrentProcessingLine.end(),
- queue->begin(), it);
+ cmAppend(this->CurrentProcessingLine, queue->begin(), it);
this->CurrentProcessingLine.push_back(0);
- const char* line = &*this->CurrentProcessingLine.begin();
+ const char* line = this->CurrentProcessingLine.data();
// Process the line
int lineType = this->ProcessSingleLine(line);
diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h
index a9b121b24..722c59009 100644
--- a/Source/CTest/cmCTestBuildHandler.h
+++ b/Source/CTest/cmCTestBuildHandler.h
@@ -52,7 +52,7 @@ private:
//! Run command specialized for make and configure. Returns process status
// and retVal is return value or exception.
- int RunMakeCommand(const char* command, int* retVal, const char* dir,
+ int RunMakeCommand(const std::string& command, int* retVal, const char* dir,
int timeout, std::ostream& ofs,
Encoding encoding = cmProcessOutput::Auto);
diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx
index 6e8f73f83..9c038399e 100644
--- a/Source/CTest/cmCTestCVS.cxx
+++ b/Source/CTest/cmCTestCVS.cxx
@@ -78,7 +78,7 @@ bool cmCTestCVS::UpdateImpl()
opts = "-dP";
}
}
- std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
// Specify the start time for nightly testing.
if (this->CTest->GetTestModel() == cmCTest::NIGHTLY) {
diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx
index 7b5c3bcb5..74a932a65 100644
--- a/Source/CTest/cmCTestConfigureCommand.cxx
+++ b/Source/CTest/cmCTestConfigureCommand.cxx
@@ -3,7 +3,7 @@
#include "cmCTestConfigureCommand.h"
#include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
+#include "cmCTestConfigureHandler.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
@@ -142,13 +142,8 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
labelsForSubprojects, this->Quiet);
}
- cmCTestGenericHandler* handler =
- this->CTest->GetInitializedHandler("configure");
- if (!handler) {
- this->SetError(
- "internal CTest error. Cannot instantiate configure handler");
- return nullptr;
- }
+ cmCTestConfigureHandler* handler = this->CTest->GetConfigureHandler();
+ handler->Initialize();
handler->SetQuiet(this->Quiet);
return handler;
}
diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx
index 6b7601b6e..7e93189cd 100644
--- a/Source/CTest/cmCTestConfigureHandler.cxx
+++ b/Source/CTest/cmCTestConfigureHandler.cxx
@@ -61,7 +61,7 @@ int cmCTestConfigureHandler::ProcessHandler()
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Configure with command: " << cCommand << std::endl,
this->Quiet);
- res = this->CTest->RunMakeCommand(cCommand.c_str(), output, &retVal,
+ res = this->CTest->RunMakeCommand(cCommand, output, &retVal,
buildDirectory.c_str(),
cmDuration::zero(), ofs);
diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx
index d2003baa3..07aae768c 100644
--- a/Source/CTest/cmCTestCoverageCommand.cxx
+++ b/Source/CTest/cmCTestCoverageCommand.cxx
@@ -19,12 +19,8 @@ cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler()
this->CTest->SetCTestConfigurationFromCMakeVariable(
this->Makefile, "CoverageExtraFlags", "CTEST_COVERAGE_EXTRA_FLAGS",
this->Quiet);
- cmCTestCoverageHandler* handler = static_cast<cmCTestCoverageHandler*>(
- this->CTest->GetInitializedHandler("coverage"));
- if (!handler) {
- this->SetError("internal CTest error. Cannot instantiate test handler");
- return nullptr;
- }
+ cmCTestCoverageHandler* handler = this->CTest->GetCoverageHandler();
+ handler->Initialize();
// If a LABELS option was given, select only files with the labels.
if (this->LabelsMentioned) {
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index 225383ce0..f6028c4fc 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestCoverageHandler.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmDuration.h"
#include "cmGeneratedFileStream.h"
@@ -52,6 +53,8 @@ public:
}
cmsysProcess_Delete(this->Process);
}
+ cmCTestRunProcess(const cmCTestRunProcess&) = delete;
+ cmCTestRunProcess& operator=(const cmCTestRunProcess&) = delete;
void SetCommand(const char* command)
{
this->CommandLineStrings.clear();
@@ -72,7 +75,7 @@ public:
args.push_back(cl.c_str());
}
args.push_back(nullptr); // null terminate
- cmsysProcess_SetCommand(this->Process, &*args.begin());
+ cmsysProcess_SetCommand(this->Process, args.data());
if (!this->WorkingDirectory.empty()) {
cmsysProcess_SetWorkingDirectory(this->Process,
this->WorkingDirectory.c_str());
@@ -223,7 +226,7 @@ bool cmCTestCoverageHandler::ShouldIDoCoverage(std::string const& file,
checkDir = fBinDir;
}
std::string ndc = cmSystemTools::FileExistsInParentDirectories(
- ".NoDartCoverage", fFile.c_str(), checkDir.c_str());
+ ".NoDartCoverage", fFile, checkDir);
if (!ndc.empty()) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Found: " << ndc << " so skip coverage of " << file
@@ -254,8 +257,8 @@ bool cmCTestCoverageHandler::ShouldIDoCoverage(std::string const& file,
return true;
}
- ndc = cmSystemTools::FileExistsInParentDirectories(
- ".NoDartCoverage", fFile.c_str(), checkDir.c_str());
+ ndc = cmSystemTools::FileExistsInParentDirectories(".NoDartCoverage", fFile,
+ checkDir);
if (!ndc.empty()) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Found: " << ndc << " so skip coverage of: " << file
@@ -786,6 +789,9 @@ struct cmCTestCoverageHandlerLocale
cmSystemTools::UnsetEnv("LC_ALL");
}
}
+ cmCTestCoverageHandlerLocale(const cmCTestCoverageHandlerLocale&) = delete;
+ cmCTestCoverageHandlerLocale& operator=(
+ const cmCTestCoverageHandlerLocale&) = delete;
std::string lc_all;
};
@@ -808,15 +814,11 @@ int cmCTestCoverageHandler::HandleJacocoCoverage(
// ...and in the binary directory.
cmsys::Glob g2;
- std::vector<std::string> binFiles;
g2.SetRecurse(true);
std::string binaryDir = this->CTest->GetCTestConfiguration("BuildDirectory");
std::string binCoverageFile = binaryDir + "/*jacoco.xml";
g2.FindFiles(binCoverageFile);
- binFiles = g2.GetFiles();
- if (!binFiles.empty()) {
- files.insert(files.end(), binFiles.begin(), binFiles.end());
- }
+ cmAppend(files, g2.GetFiles());
if (!files.empty()) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
@@ -999,7 +1001,7 @@ int cmCTestCoverageHandler::HandleGCovCoverage(
static_cast<void>(locale_C);
std::vector<std::string> basecovargs =
- cmSystemTools::ParseArguments(gcovExtraFlags.c_str());
+ cmSystemTools::ParseArguments(gcovExtraFlags);
basecovargs.insert(basecovargs.begin(), gcovCommand);
basecovargs.emplace_back("-o");
@@ -1058,8 +1060,7 @@ int cmCTestCoverageHandler::HandleGCovCoverage(
this->Quiet);
std::vector<std::string> lines;
-
- cmSystemTools::Split(output.c_str(), lines);
+ cmsys::SystemTools::Split(output, lines);
for (std::string const& line : lines) {
std::string sourceFile;
@@ -1373,7 +1374,7 @@ int cmCTestCoverageHandler::HandleLCovCoverage(
static_cast<void>(locale_C);
std::vector<std::string> covargs =
- cmSystemTools::ParseArguments(lcovExtraFlags.c_str());
+ cmSystemTools::ParseArguments(lcovExtraFlags);
covargs.insert(covargs.begin(), lcovCommand);
const std::string command = joinCommandLine(covargs);
@@ -1435,8 +1436,7 @@ int cmCTestCoverageHandler::HandleLCovCoverage(
this->Quiet);
std::vector<std::string> lines;
-
- cmSystemTools::Split(output.c_str(), lines);
+ cmsys::SystemTools::Split(output, lines);
for (std::string const& line : lines) {
std::string sourceFile;
@@ -1462,8 +1462,7 @@ int cmCTestCoverageHandler::HandleLCovCoverage(
" looking for LCOV files in: " << daGlob << std::endl, this->Quiet);
gl.FindFiles(daGlob);
// Keep a list of all LCOV files
- lcovFiles.insert(lcovFiles.end(), gl.GetFiles().begin(),
- gl.GetFiles().end());
+ cmAppend(lcovFiles, gl.GetFiles());
for (std::string const& file : lcovFiles) {
lcovFile = file;
@@ -1601,11 +1600,11 @@ void cmCTestCoverageHandler::FindGCovFiles(std::vector<std::string>& files)
std::string daGlob = lm.first;
daGlob += "/*.da";
gl.FindFiles(daGlob);
- files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
+ cmAppend(files, gl.GetFiles());
daGlob = lm.first;
daGlob += "/*.gcda";
gl.FindFiles(daGlob);
- files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
+ cmAppend(files, gl.GetFiles());
}
}
@@ -1642,7 +1641,7 @@ bool cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files)
"Error while finding files matching " << daGlob << std::endl);
return false;
}
- files.insert(files.end(), gl.GetFiles().begin(), gl.GetFiles().end());
+ cmAppend(files, gl.GetFiles());
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Now searching in: " << daGlob << std::endl, this->Quiet);
return true;
diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx
index 6eb43546d..cc63e4563 100644
--- a/Source/CTest/cmCTestCurl.cxx
+++ b/Source/CTest/cmCTestCurl.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestCurl.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCurl.h"
#include "cmSystemTools.h"
@@ -43,19 +44,15 @@ size_t curlWriteMemoryCallback(void* ptr, size_t size, size_t nmemb,
void* data)
{
int realsize = static_cast<int>(size * nmemb);
-
- std::vector<char>* vec = static_cast<std::vector<char>*>(data);
const char* chPtr = static_cast<char*>(ptr);
- vec->insert(vec->end(), chPtr, chPtr + realsize);
+ cmAppend(*static_cast<std::vector<char>*>(data), chPtr, chPtr + realsize);
return realsize;
}
size_t curlDebugCallback(CURL* /*unused*/, curl_infotype /*unused*/,
char* chPtr, size_t size, void* data)
{
- std::vector<char>* vec = static_cast<std::vector<char>*>(data);
- vec->insert(vec->end(), chPtr, chPtr + size);
-
+ cmAppend(*static_cast<std::vector<char>*>(data), chPtr, chPtr + size);
return size;
}
}
diff --git a/Source/CTest/cmCTestCurl.h b/Source/CTest/cmCTestCurl.h
index 86d948995..6186af8d2 100644
--- a/Source/CTest/cmCTestCurl.h
+++ b/Source/CTest/cmCTestCurl.h
@@ -16,6 +16,8 @@ class cmCTestCurl
public:
cmCTestCurl(cmCTest*);
~cmCTestCurl();
+ cmCTestCurl(const cmCTestCurl&) = delete;
+ cmCTestCurl& operator=(const cmCTestCurl&) = delete;
bool UploadFile(std::string const& local_file, std::string const& url,
std::string const& fields, std::string& response);
bool HttpRequest(std::string const& url, std::string const& fields,
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
index 210abe55b..9d9761ce2 100644
--- a/Source/CTest/cmCTestGIT.cxx
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -162,7 +162,7 @@ bool cmCTestGIT::UpdateByFetchAndReset()
if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("GITUpdateOptions");
}
- std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
for (std::string const& arg : args) {
git_fetch.push_back(arg.c_str());
}
@@ -547,7 +547,7 @@ private:
{
// Look for header fields that we need.
if (cmHasLiteralPrefix(this->Line, "commit ")) {
- this->Rev.Rev = this->Line.c_str() + 7;
+ this->Rev.Rev = this->Line.substr(7);
} else if (cmHasLiteralPrefix(this->Line, "author ")) {
Person author;
this->ParsePerson(this->Line.c_str() + 7, author);
diff --git a/Source/CTest/cmCTestGlobalVC.cxx b/Source/CTest/cmCTestGlobalVC.cxx
index a2d4d2c75..54ebd4f0c 100644
--- a/Source/CTest/cmCTestGlobalVC.cxx
+++ b/Source/CTest/cmCTestGlobalVC.cxx
@@ -117,3 +117,8 @@ bool cmCTestGlobalVC::WriteXMLUpdates(cmXMLWriter& xml)
return result;
}
+
+void cmCTestGlobalVC::SetNewRevision(std::string const& revision)
+{
+ this->NewRevision = revision;
+}
diff --git a/Source/CTest/cmCTestGlobalVC.h b/Source/CTest/cmCTestGlobalVC.h
index 76377ed17..9c572152e 100644
--- a/Source/CTest/cmCTestGlobalVC.h
+++ b/Source/CTest/cmCTestGlobalVC.h
@@ -32,6 +32,8 @@ protected:
// Implement cmCTestVC internal API.
bool WriteXMLUpdates(cmXMLWriter& xml) override;
+ void SetNewRevision(std::string const& revision) override;
+
/** Represent a vcs-reported action for one path in a revision. */
struct Change
{
diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx
index 6fb99d864..ba2252a30 100644
--- a/Source/CTest/cmCTestHG.cxx
+++ b/Source/CTest/cmCTestHG.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestHG.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCTestVC.h"
#include "cmProcessTools.h"
@@ -144,7 +145,7 @@ bool cmCTestHG::UpdateImpl()
if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("HGUpdateOptions");
}
- std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
for (std::string const& arg : args) {
hg_update.push_back(arg.c_str());
}
@@ -202,7 +203,7 @@ private:
void CharacterDataHandler(const char* data, int length) override
{
- this->CData.insert(this->CData.end(), data, data + length);
+ cmAppend(this->CData, data, data + length);
}
void EndElement(const std::string& name) override
diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx
index 57a14efd1..adf955399 100644
--- a/Source/CTest/cmCTestHandlerCommand.cxx
+++ b/Source/CTest/cmCTestHandlerCommand.cxx
@@ -76,6 +76,8 @@ public:
}
}
}
+ SaveRestoreErrorState(const SaveRestoreErrorState&) = delete;
+ SaveRestoreErrorState& operator=(const SaveRestoreErrorState&) = delete;
private:
bool InitialErrorState;
diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
index 5e66e056a..a96513e8c 100644
--- a/Source/CTest/cmCTestLaunch.cxx
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -308,7 +308,7 @@ void cmCTestLaunch::LoadLabels()
if (line[0] == ' ') {
// Label lines appear indented by one space.
if (inTarget || inSource) {
- this->Labels.insert(line.c_str() + 1);
+ this->Labels.insert(line.substr(1));
}
} else if (!this->OptionSource.empty() && !inSource) {
// Non-indented lines specify a source file name. The first one
diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h
index debbe59d7..107fd6174 100644
--- a/Source/CTest/cmCTestLaunch.h
+++ b/Source/CTest/cmCTestLaunch.h
@@ -28,6 +28,9 @@ private:
cmCTestLaunch(int argc, const char* const* argv);
~cmCTestLaunch();
+ cmCTestLaunch(const cmCTestLaunch&) = delete;
+ cmCTestLaunch& operator=(const cmCTestLaunch&) = delete;
+
// Run the real command.
int Run();
void RunChild();
diff --git a/Source/CTest/cmCTestMemCheckCommand.cxx b/Source/CTest/cmCTestMemCheckCommand.cxx
index a5d599583..7dad1cec5 100644
--- a/Source/CTest/cmCTestMemCheckCommand.cxx
+++ b/Source/CTest/cmCTestMemCheckCommand.cxx
@@ -7,7 +7,6 @@
#include <vector>
#include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
#include "cmCTestMemCheckHandler.h"
#include "cmMakefile.h"
@@ -20,8 +19,8 @@ cmCTestMemCheckCommand::cmCTestMemCheckCommand()
cmCTestGenericHandler* cmCTestMemCheckCommand::InitializeActualHandler()
{
- cmCTestGenericHandler* handler =
- this->CTest->GetInitializedHandler("memcheck");
+ cmCTestMemCheckHandler* handler = this->CTest->GetMemCheckHandler();
+ handler->Initialize();
this->CTest->SetCTestConfigurationFromCMakeVariable(
this->Makefile, "MemoryCheckType", "CTEST_MEMORYCHECK_TYPE", this->Quiet);
diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx
index 8ba59d3f9..b09e7bb22 100644
--- a/Source/CTest/cmCTestMemCheckHandler.cxx
+++ b/Source/CTest/cmCTestMemCheckHandler.cxx
@@ -520,7 +520,7 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
this->CTest->GetCTestConfiguration("ValgrindCommandOptions");
}
this->MemoryTesterOptions =
- cmSystemTools::ParseArguments(memoryTesterOptions.c_str());
+ cmSystemTools::ParseArguments(memoryTesterOptions);
this->MemoryTesterOutputFile =
this->CTest->GetBinaryDir() + "/Testing/Temporary/MemoryChecker.??.log";
@@ -725,7 +725,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckSanitizerOutput(
cmsys::RegularExpression leakWarning("(Direct|Indirect) leak of .*");
int defects = 0;
std::vector<std::string> lines;
- cmSystemTools::Split(str.c_str(), lines);
+ cmsys::SystemTools::Split(str, lines);
std::ostringstream ostr;
log.clear();
for (std::string const& l : lines) {
@@ -755,7 +755,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
const std::string& str, std::string& log, std::vector<int>& results)
{
std::vector<std::string> lines;
- cmSystemTools::Split(str.c_str(), lines);
+ cmsys::SystemTools::Split(str, lines);
std::ostringstream ostr;
log.clear();
@@ -798,7 +798,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
const std::string& str, std::string& log, std::vector<int>& results)
{
std::vector<std::string> lines;
- cmSystemTools::Split(str.c_str(), lines);
+ cmsys::SystemTools::Split(str, lines);
bool unlimitedOutput = false;
if (str.find("CTEST_FULL_OUTPUT") != std::string::npos ||
this->CustomMaximumFailedTestOutputSize == 0) {
@@ -815,9 +815,9 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
cmsys::RegularExpression valgrindLine("^==[0-9][0-9]*==");
cmsys::RegularExpression vgFIM(
- "== .*Invalid free\\(\\) / delete / delete\\[\\]");
+ R"(== .*Invalid free\(\) / delete / delete\[\])");
cmsys::RegularExpression vgFMM(
- "== .*Mismatched free\\(\\) / delete / delete \\[\\]");
+ R"(== .*Mismatched free\(\) / delete / delete \[\])");
cmsys::RegularExpression vgMLK1(
"== .*[0-9,]+ bytes in [0-9,]+ blocks are definitely lost"
" in loss record [0-9,]+ of [0-9,]+");
@@ -937,7 +937,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput(
log.clear();
auto sttime = std::chrono::steady_clock::now();
std::vector<std::string> lines;
- cmSystemTools::Split(str.c_str(), lines);
+ cmsys::SystemTools::Split(str, lines);
cmCTestOptionalLog(this->CTest, DEBUG,
"Start test: " << lines.size() << std::endl, this->Quiet);
std::vector<std::string>::size_type cc;
diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h
index 8880dac9a..746d72c01 100644
--- a/Source/CTest/cmCTestMemCheckHandler.h
+++ b/Source/CTest/cmCTestMemCheckHandler.h
@@ -114,7 +114,7 @@ private:
// this type of checker
void InitializeResultsVectors();
- ///! Initialize memory checking subsystem.
+ //! Initialize memory checking subsystem.
bool InitializeMemoryChecking();
/**
@@ -143,11 +143,11 @@ private:
void PostProcessTest(cmCTestTestResult& res, int test);
void PostProcessBoundsCheckerTest(cmCTestTestResult& res, int test);
- ///! append MemoryTesterOutputFile to the test log
+ //! append MemoryTesterOutputFile to the test log
void AppendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res,
std::string const& filename);
- ///! generate the output filename for the given test index
+ //! generate the output filename for the given test index
void TestOutputFileNames(int test, std::vector<std::string>& files);
};
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 756ac6cf6..ef63073b1 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -3,11 +3,13 @@
#include "cmCTestMultiProcessHandler.h"
#include "cmAffinity.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCTestRunTest.h"
#include "cmCTestTestHandler.h"
#include "cmDuration.h"
#include "cmListFileCache.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
#include "cmWorkingDirectory.h"
@@ -108,8 +110,8 @@ void cmCTestMultiProcessHandler::SetTestLoad(unsigned long load)
fake_load_value)) {
if (!cmSystemTools::StringToULong(fake_load_value.c_str(),
&this->FakeLoadForTesting)) {
- cmSystemTools::Error("Failed to parse fake load value: ",
- fake_load_value.c_str());
+ cmSystemTools::Error("Failed to parse fake load value: " +
+ fake_load_value);
}
}
}
@@ -651,16 +653,11 @@ void cmCTestMultiProcessHandler::CreateParallelTestCostList()
// Reverse iterate over the different dependency levels (deepest first).
// Sort tests within each level by COST and append them to the cost list.
- for (std::list<TestSet>::reverse_iterator i = priorityStack.rbegin();
- i != priorityStack.rend(); ++i) {
- TestSet const& currentSet = *i;
- TestComparator comp(this);
-
+ for (TestSet const& currentSet : cmReverseRange(priorityStack)) {
TestList sortedCopy;
-
- sortedCopy.insert(sortedCopy.end(), currentSet.begin(), currentSet.end());
-
- std::stable_sort(sortedCopy.begin(), sortedCopy.end(), comp);
+ cmAppend(sortedCopy, currentSet);
+ std::stable_sort(sortedCopy.begin(), sortedCopy.end(),
+ TestComparator(this));
for (auto const& j : sortedCopy) {
if (alreadySortedTests.find(j) == alreadySortedTests.end()) {
@@ -689,8 +686,8 @@ void cmCTestMultiProcessHandler::CreateSerialTestCostList()
presortedList.push_back(i.first);
}
- TestComparator comp(this);
- std::stable_sort(presortedList.begin(), presortedList.end(), comp);
+ std::stable_sort(presortedList.begin(), presortedList.end(),
+ TestComparator(this));
TestSet alreadySortedTests;
@@ -993,7 +990,7 @@ static Json::Value DumpCTestInfo(
const std::vector<std::string>& args = testRun.GetArguments();
if (!args.empty()) {
commandAndArgs.reserve(args.size() + 1);
- commandAndArgs.insert(commandAndArgs.end(), args.begin(), args.end());
+ cmAppend(commandAndArgs, args);
}
testInfo["command"] = DumpToJsonArray(commandAndArgs);
}
diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx
index 435be97b6..2eb8dba29 100644
--- a/Source/CTest/cmCTestP4.cxx
+++ b/Source/CTest/cmCTestP4.cxx
@@ -2,9 +2,11 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestP4.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCTestVC.h"
#include "cmProcessTools.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
#include "cmsys/RegularExpression.hxx"
@@ -193,7 +195,7 @@ public:
{
this->SetLog(&P4->Log, prefix);
this->RegexHeader.compile("^Change ([0-9]+) by (.+)@(.+) on (.*)$");
- this->RegexDiff.compile("^\\.\\.\\. (.*)#[0-9]+ ([^ ]+)$");
+ this->RegexDiff.compile(R"(^\.\.\. (.*)#[0-9]+ ([^ ]+)$)");
}
private:
@@ -323,10 +325,7 @@ void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions)
// The CTEST_P4_OPTIONS variable adds additional Perforce command line
// options before the main command
std::string opts = this->CTest->GetCTestConfiguration("P4Options");
- std::vector<std::string> args =
- cmSystemTools::ParseArguments(opts.c_str());
-
- P4Options.insert(P4Options.end(), args.begin(), args.end());
+ cmAppend(P4Options, cmSystemTools::ParseArguments(opts));
}
CommandOptions.clear();
@@ -425,12 +424,11 @@ bool cmCTestP4::LoadRevisions()
// p4 describe -s ...@1111111,2222222
std::vector<char const*> p4_describe;
- for (std::vector<std::string>::reverse_iterator i = ChangeLists.rbegin();
- i != ChangeLists.rend(); ++i) {
+ for (std::string const& i : cmReverseRange(ChangeLists)) {
SetP4Options(p4_describe);
p4_describe.push_back("describe");
p4_describe.push_back("-s");
- p4_describe.push_back(i->c_str());
+ p4_describe.push_back(i.c_str());
p4_describe.push_back(nullptr);
DescribeParser outDescribe(this, "p4_describe-out> ");
@@ -501,7 +499,7 @@ bool cmCTestP4::UpdateImpl()
if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("P4UpdateOptions");
}
- std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
for (std::string const& arg : args) {
p4_sync.push_back(arg.c_str());
}
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 7f081ef89..31976b994 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -9,11 +9,10 @@
#include "cmSystemTools.h"
#include "cmWorkingDirectory.h"
-#include "cm_zlib.h"
-#include "cmsys/Base64.h"
#include "cmsys/RegularExpression.hxx"
#include <chrono>
#include <cmAlgorithms.h>
+#include <cstdint>
#include <cstring>
#include <iomanip>
#include <ratio>
@@ -31,9 +30,6 @@ cmCTestRunTest::cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler)
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
this->TestResult.TestCount = 0;
this->TestResult.Properties = nullptr;
- this->ProcessOutput.clear();
- this->CompressedOutput.clear();
- this->CompressionRatio = 2;
this->NumberOfRunsLeft = 1; // default to 1 run of the test
this->RunUntilFail = false; // default to run the test once
this->RunAgain = false; // default to not having to run again
@@ -68,73 +64,8 @@ void cmCTestRunTest::CheckOutput(std::string const& line)
}
}
-// Streamed compression of test output. The compressed data
-// is appended to this->CompressedOutput
-void cmCTestRunTest::CompressOutput()
-{
- int ret;
- z_stream strm;
-
- unsigned char* in = reinterpret_cast<unsigned char*>(
- const_cast<char*>(this->ProcessOutput.c_str()));
- // zlib makes the guarantee that this is the maximum output size
- int outSize = static_cast<int>(
- static_cast<double>(this->ProcessOutput.size()) * 1.001 + 13.0);
- unsigned char* out = new unsigned char[outSize];
-
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- ret = deflateInit(&strm, -1); // default compression level
- if (ret != Z_OK) {
- delete[] out;
- return;
- }
-
- strm.avail_in = static_cast<uInt>(this->ProcessOutput.size());
- strm.next_in = in;
- strm.avail_out = outSize;
- strm.next_out = out;
- ret = deflate(&strm, Z_FINISH);
-
- if (ret != Z_STREAM_END) {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error during output compression. Sending uncompressed output."
- << std::endl);
- delete[] out;
- return;
- }
-
- (void)deflateEnd(&strm);
-
- unsigned char* encoded_buffer =
- new unsigned char[static_cast<int>(outSize * 1.5)];
-
- size_t rlen = cmsysBase64_Encode(out, strm.total_out, encoded_buffer, 1);
-
- this->CompressedOutput.clear();
- for (size_t i = 0; i < rlen; i++) {
- this->CompressedOutput += encoded_buffer[i];
- }
-
- if (strm.total_in) {
- this->CompressionRatio =
- static_cast<double>(strm.total_out) / static_cast<double>(strm.total_in);
- }
-
- delete[] encoded_buffer;
- delete[] out;
-}
-
bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
{
- if ((!this->TestHandler->MemCheck &&
- this->CTest->ShouldCompressTestOutput()) ||
- (this->TestHandler->MemCheck &&
- this->CTest->ShouldCompressTestOutput())) {
- this->CompressOutput();
- }
-
this->WriteLogOutputTop(completed, total);
std::string reason;
bool passed = true;
@@ -143,7 +74,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
if (res != cmProcess::State::Expired) {
this->TimeoutIsForStopTime = false;
}
- int retVal = this->TestProcess->GetExitValue();
+ std::int64_t retVal = this->TestProcess->GetExitValue();
bool forceFail = false;
bool skipped = false;
bool outputTestErrorsToConsole = false;
@@ -201,14 +132,17 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
} else {
this->TestResult.Status = cmCTestTestHandler::FAILED;
outputStream << "***Failed " << reason;
- outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
+ outputTestErrorsToConsole =
+ this->CTest->GetOutputTestOutputOnTestFailure();
}
} else if (res == cmProcess::State::Expired) {
outputStream << "***Timeout ";
this->TestResult.Status = cmCTestTestHandler::TIMEOUT;
- outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
+ outputTestErrorsToConsole =
+ this->CTest->GetOutputTestOutputOnTestFailure();
} else if (res == cmProcess::State::Exception) {
- outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
+ outputTestErrorsToConsole =
+ this->CTest->GetOutputTestOutputOnTestFailure();
outputStream << "***Exception: ";
this->TestResult.ExceptionStatus =
this->TestProcess->GetExitExceptionString();
@@ -335,10 +269,18 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
// if the test actually started and ran
// record the results in TestResult
if (started) {
- bool compress = !this->TestHandler->MemCheck &&
- this->CompressionRatio < 1 && this->CTest->ShouldCompressTestOutput();
+ std::string compressedOutput;
+ if (!this->TestHandler->MemCheck &&
+ this->CTest->ShouldCompressTestOutput()) {
+ std::string str = this->ProcessOutput;
+ if (this->CTest->CompressString(str)) {
+ compressedOutput = std::move(str);
+ }
+ }
+ bool compress = !compressedOutput.empty() &&
+ compressedOutput.length() < this->ProcessOutput.length();
this->TestResult.Output =
- compress ? this->CompressedOutput : this->ProcessOutput;
+ compress ? compressedOutput : this->ProcessOutput;
this->TestResult.CompressOutput = compress;
this->TestResult.ReturnValue = this->TestProcess->GetExitValue();
if (!skipped) {
@@ -493,32 +435,26 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
this->ProcessOutput.clear();
+ this->TestResult.Properties = this->TestProperties;
+ this->TestResult.ExecutionTime = cmDuration::zero();
+ this->TestResult.CompressOutput = false;
+ this->TestResult.ReturnValue = -1;
+ this->TestResult.TestCount = this->TestProperties->Index;
+ this->TestResult.Name = this->TestProperties->Name;
+ this->TestResult.Path = this->TestProperties->Directory;
+
// Return immediately if test is disabled
if (this->TestProperties->Disabled) {
- this->TestResult.Properties = this->TestProperties;
- this->TestResult.ExecutionTime = cmDuration::zero();
- this->TestResult.CompressOutput = false;
- this->TestResult.ReturnValue = -1;
this->TestResult.CompletionStatus = "Disabled";
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
- this->TestResult.TestCount = this->TestProperties->Index;
- this->TestResult.Name = this->TestProperties->Name;
- this->TestResult.Path = this->TestProperties->Directory;
this->TestProcess = cm::make_unique<cmProcess>(*this);
this->TestResult.Output = "Disabled";
this->TestResult.FullCommandLine.clear();
return false;
}
- this->TestResult.Properties = this->TestProperties;
- this->TestResult.ExecutionTime = cmDuration::zero();
- this->TestResult.CompressOutput = false;
- this->TestResult.ReturnValue = -1;
this->TestResult.CompletionStatus = "Failed to start";
this->TestResult.Status = cmCTestTestHandler::BAD_COMMAND;
- this->TestResult.TestCount = this->TestProperties->Index;
- this->TestResult.Name = this->TestProperties->Name;
- this->TestResult.Path = this->TestProperties->Directory;
// Check for failed fixture dependencies before we even look at the command
// arguments because if we are not going to run the test, the command and
@@ -696,9 +632,8 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
{
this->TestProcess = cm::make_unique<cmProcess>(*this);
this->TestProcess->SetId(this->Index);
- this->TestProcess->SetWorkingDirectory(
- this->TestProperties->Directory.c_str());
- this->TestProcess->SetCommand(this->ActualCommand.c_str());
+ this->TestProcess->SetWorkingDirectory(this->TestProperties->Directory);
+ this->TestProcess->SetCommand(this->ActualCommand);
this->TestProcess->SetCommandArguments(this->Arguments);
// determine how much time we have
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index 918d5fa58..38cc417e5 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -58,9 +58,6 @@ public:
// Read and store output. Returns true if it must be called again.
void CheckOutput(std::string const& line);
- // Compresses the output, writing to CompressedOutput
- void CompressOutput();
-
// launch the test process, return whether it started correctly
bool StartTest(size_t completed, size_t total);
// capture and report the test results
@@ -105,8 +102,6 @@ private:
cmCTest* CTest;
std::unique_ptr<cmProcess> TestProcess;
std::string ProcessOutput;
- std::string CompressedOutput;
- double CompressionRatio;
// The test results
cmCTestTestHandler::cmCTestTestResult TestResult;
cmCTestMultiProcessHandler& MultiTestHandler;
diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx
index 3bf66ca23..c834686d7 100644
--- a/Source/CTest/cmCTestSVN.cxx
+++ b/Source/CTest/cmCTestSVN.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestSVN.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCTestVC.h"
#include "cmProcessTools.h"
@@ -242,7 +243,7 @@ bool cmCTestSVN::UpdateImpl()
if (opts.empty()) {
opts = this->CTest->GetCTestConfiguration("SVNUpdateOptions");
}
- std::vector<std::string> args = cmSystemTools::ParseArguments(opts.c_str());
+ std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
// Specify the start time for nightly testing.
if (this->CTest->GetTestModel() == cmCTest::NIGHTLY) {
@@ -269,15 +270,13 @@ bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters,
std::vector<char const*> args;
args.push_back(this->CommandLineTool.c_str());
-
- args.insert(args.end(), parameters.begin(), parameters.end());
-
+ cmAppend(args, parameters);
args.push_back("--non-interactive");
std::string userOptions = this->CTest->GetCTestConfiguration("SVNOptions");
std::vector<std::string> parsedUserOptions =
- cmSystemTools::ParseArguments(userOptions.c_str());
+ cmSystemTools::ParseArguments(userOptions);
for (std::string const& opt : parsedUserOptions) {
args.push_back(opt.c_str());
}
@@ -344,7 +343,7 @@ private:
void CharacterDataHandler(const char* data, int length) override
{
- this->CData.insert(this->CData.end(), data, data + length);
+ cmAppend(this->CData, data, data + length);
}
void EndElement(const std::string& name) override
@@ -515,7 +514,7 @@ private:
if (path.size() > this->SVN->SourceDirectory.size() &&
strncmp(path.c_str(), this->SVN->SourceDirectory.c_str(),
this->SVN->SourceDirectory.size()) == 0) {
- local_path = path.c_str() + this->SVN->SourceDirectory.size() + 1;
+ local_path = path.substr(this->SVN->SourceDirectory.size() + 1);
} else {
local_path = path;
}
@@ -554,7 +553,7 @@ std::string cmCTestSVN::SVNInfo::BuildLocalPath(std::string const& path) const
// Add path with base prefix removed
if (path.size() > this->Base.size() &&
strncmp(path.c_str(), this->Base.c_str(), this->Base.size()) == 0) {
- local_path += (path.c_str() + this->Base.size());
+ local_path += path.substr(this->Base.size());
} else {
local_path += path;
}
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 33b8b4a4c..a739f440c 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -199,7 +199,7 @@ int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
// Now create process object
cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetCommand(cp, argv.data());
// cmsysProcess_SetWorkingDirectory(cp, dir);
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
// cmsysProcess_SetTimeout(cp, timeout);
@@ -288,11 +288,12 @@ void cmCTestScriptHandler::CreateCMake()
this->ParentMakefile->GetRecursionDepth());
}
- this->CMake->SetProgressCallback([this](const char* m, float /*unused*/) {
- if (m && *m) {
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "-- " << m << std::endl);
- }
- });
+ this->CMake->SetProgressCallback(
+ [this](const std::string& m, float /*unused*/) {
+ if (!m.empty()) {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "-- " << m << std::endl);
+ }
+ });
this->AddCTestCommand("ctest_build", new cmCTestBuildCommand);
this->AddCTestCommand("ctest_configure", new cmCTestConfigureCommand);
@@ -330,7 +331,7 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
}
// make sure the file exists
if (!cmSystemTools::FileExists(script)) {
- cmSystemTools::Error("Cannot find file: ", script.c_str());
+ cmSystemTools::Error("Cannot find file: " + script);
return 1;
}
@@ -446,7 +447,8 @@ int cmCTestScriptHandler::ExtractVariables()
if (updateVal) {
if (this->UpdateCmd.empty()) {
cmSystemTools::Error(
- updateVar, " specified without specifying CTEST_CVS_COMMAND.");
+ std::string(updateVar) +
+ " specified without specifying CTEST_CVS_COMMAND.");
return 12;
}
this->ExtraUpdates.emplace_back(updateVal);
@@ -470,8 +472,8 @@ int cmCTestScriptHandler::ExtractVariables()
msg += "\nCTEST_COMMAND = ";
msg += (!this->CTestCmd.empty()) ? this->CTestCmd.c_str() : "(Null)";
cmSystemTools::Error(
- "Some required settings in the configuration file were missing:\n",
- msg.c_str());
+ "Some required settings in the configuration file were missing:\n" +
+ msg);
return 4;
}
@@ -607,12 +609,10 @@ int cmCTestScriptHandler::CheckOutSourceDir()
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Run cvs: " << this->CVSCheckOut << std::endl);
res = cmSystemTools::RunSingleCommand(
- this->CVSCheckOut.c_str(), &output, &output, &retVal,
- this->CTestRoot.c_str(), this->HandlerVerbose,
- cmDuration::zero() /*this->TimeOut*/);
+ this->CVSCheckOut, &output, &output, &retVal, this->CTestRoot.c_str(),
+ this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
if (!res || retVal != 0) {
- cmSystemTools::Error("Unable to perform cvs checkout:\n",
- output.c_str());
+ cmSystemTools::Error("Unable to perform cvs checkout:\n" + output);
return 6;
}
}
@@ -675,11 +675,11 @@ int cmCTestScriptHandler::PerformExtraUpdates()
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Run Update: " << fullCommand << std::endl);
res = cmSystemTools::RunSingleCommand(
- fullCommand.c_str(), &output, &output, &retVal, cvsArgs[0].c_str(),
+ fullCommand, &output, &output, &retVal, cvsArgs[0].c_str(),
this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
if (!res || retVal != 0) {
- cmSystemTools::Error("Unable to perform extra updates:\n", eu.c_str(),
- "\nWith output:\n", output.c_str());
+ cmSystemTools::Error("Unable to perform extra updates:\n" + eu +
+ "\nWith output:\n" + output);
return 0;
}
}
@@ -721,8 +721,8 @@ int cmCTestScriptHandler::RunConfigurationDashboard()
if (!cmSystemTools::FileExists(this->BinaryDir) &&
this->SourceDir != this->BinaryDir) {
if (!cmSystemTools::MakeDirectory(this->BinaryDir)) {
- cmSystemTools::Error("Unable to create the binary directory:\n",
- this->BinaryDir.c_str());
+ cmSystemTools::Error("Unable to create the binary directory:\n" +
+ this->BinaryDir);
this->RestoreBackupDirectories();
return 7;
}
@@ -779,7 +779,7 @@ int cmCTestScriptHandler::RunConfigurationDashboard()
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Run cmake command: " << command << std::endl);
res = cmSystemTools::RunSingleCommand(
- command.c_str(), &output, &output, &retVal, this->BinaryDir.c_str(),
+ command, &output, &output, &retVal, this->BinaryDir.c_str(),
this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
if (!this->CMOutFile.empty()) {
@@ -818,7 +818,7 @@ int cmCTestScriptHandler::RunConfigurationDashboard()
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Run ctest command: " << command << std::endl);
res = cmSystemTools::RunSingleCommand(
- command.c_str(), &output, &output, &retVal, this->BinaryDir.c_str(),
+ command, &output, &output, &retVal, this->BinaryDir.c_str(),
this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
// did something critical fail in ctest
diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx
index 00c061016..afc3e67d9 100644
--- a/Source/CTest/cmCTestSubmitCommand.cxx
+++ b/Source/CTest/cmCTestSubmitCommand.cxx
@@ -3,7 +3,6 @@
#include "cmCTestSubmitCommand.h"
#include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
#include "cmCTestSubmitHandler.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
@@ -13,6 +12,29 @@
class cmExecutionStatus;
+cmCTestSubmitCommand::cmCTestSubmitCommand()
+{
+ this->PartsMentioned = false;
+ this->FilesMentioned = false;
+ this->InternalTest = false;
+ this->RetryCount = "";
+ this->RetryDelay = "";
+ this->CDashUpload = false;
+ this->Arguments[cts_BUILD_ID] = "BUILD_ID";
+ this->Last = cts_LAST;
+}
+
+/**
+ * This is a virtual constructor for the command.
+ */
+cmCommand* cmCTestSubmitCommand::Clone()
+{
+ cmCTestSubmitCommand* ni = new cmCTestSubmitCommand;
+ ni->CTest = this->CTest;
+ ni->CTestScriptHandler = this->CTestScriptHandler;
+ return ni;
+}
+
cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
{
const char* submitURL = !this->SubmitURL.empty()
@@ -42,33 +64,23 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
this->Makefile->GetDefinition("CTEST_NOTES_FILES");
if (notesFilesVariable) {
std::vector<std::string> notesFiles;
- cmCTest::VectorOfStrings newNotesFiles;
cmSystemTools::ExpandListArgument(notesFilesVariable, notesFiles);
- newNotesFiles.insert(newNotesFiles.end(), notesFiles.begin(),
- notesFiles.end());
- this->CTest->GenerateNotesFile(newNotesFiles);
+ this->CTest->GenerateNotesFile(notesFiles);
}
const char* extraFilesVariable =
this->Makefile->GetDefinition("CTEST_EXTRA_SUBMIT_FILES");
if (extraFilesVariable) {
std::vector<std::string> extraFiles;
- cmCTest::VectorOfStrings newExtraFiles;
cmSystemTools::ExpandListArgument(extraFilesVariable, extraFiles);
- newExtraFiles.insert(newExtraFiles.end(), extraFiles.begin(),
- extraFiles.end());
- if (!this->CTest->SubmitExtraFiles(newExtraFiles)) {
+ if (!this->CTest->SubmitExtraFiles(extraFiles)) {
this->SetError("problem submitting extra files.");
return nullptr;
}
}
- cmCTestGenericHandler* handler =
- this->CTest->GetInitializedHandler("submit");
- if (!handler) {
- this->SetError("internal CTest error. Cannot instantiate submit handler");
- return nullptr;
- }
+ cmCTestSubmitHandler* handler = this->CTest->GetSubmitHandler();
+ handler->Initialize();
// If no FILES or PARTS given, *all* PARTS are submitted by default.
//
@@ -90,38 +102,30 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
// But FILES with no PARTS mentioned should just submit the FILES
// without any of the default parts.
//
- std::set<cmCTest::Part> noParts;
- static_cast<cmCTestSubmitHandler*>(handler)->SelectParts(noParts);
-
- static_cast<cmCTestSubmitHandler*>(handler)->SelectFiles(this->Files);
+ handler->SelectParts(std::set<cmCTest::Part>());
+ handler->SelectFiles(this->Files);
}
// If a PARTS option was given, select only the named parts for submission.
//
if (this->PartsMentioned) {
- static_cast<cmCTestSubmitHandler*>(handler)->SelectParts(this->Parts);
+ handler->SelectParts(this->Parts);
}
// Pass along any HTTPHEADER to the handler if this option was given.
if (!this->HttpHeaders.empty()) {
- static_cast<cmCTestSubmitHandler*>(handler)->SetHttpHeaders(
- this->HttpHeaders);
+ handler->SetHttpHeaders(this->HttpHeaders);
}
- static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
- "RetryDelay", this->RetryDelay.c_str());
- static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
- "RetryCount", this->RetryCount.c_str());
- static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
- "InternalTest", this->InternalTest ? "ON" : "OFF");
+ handler->SetOption("RetryDelay", this->RetryDelay.c_str());
+ handler->SetOption("RetryCount", this->RetryCount.c_str());
+ handler->SetOption("InternalTest", this->InternalTest ? "ON" : "OFF");
handler->SetQuiet(this->Quiet);
if (this->CDashUpload) {
- static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
- "CDashUploadFile", this->CDashUploadFile.c_str());
- static_cast<cmCTestSubmitHandler*>(handler)->SetOption(
- "CDashUploadType", this->CDashUploadType.c_str());
+ handler->SetOption("CDashUploadFile", this->CDashUploadFile.c_str());
+ handler->SetOption("CDashUploadType", this->CDashUploadType.c_str());
}
return handler;
}
@@ -130,7 +134,15 @@ bool cmCTestSubmitCommand::InitialPass(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
this->CDashUpload = !args.empty() && args[0] == "CDASH_UPLOAD";
- return this->cmCTestHandlerCommand::InitialPass(args, status);
+
+ bool ret = this->cmCTestHandlerCommand::InitialPass(args, status);
+
+ if (this->Values[cts_BUILD_ID] && *this->Values[cts_BUILD_ID]) {
+ this->Makefile->AddDefinition(this->Values[cts_BUILD_ID],
+ this->CTest->GetBuildID().c_str());
+ }
+
+ return ret;
}
bool cmCTestSubmitCommand::CheckArgumentKeyword(std::string const& arg)
diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h
index 0caccd66d..1e270466d 100644
--- a/Source/CTest/cmCTestSubmitCommand.h
+++ b/Source/CTest/cmCTestSubmitCommand.h
@@ -25,26 +25,8 @@ class cmExecutionStatus;
class cmCTestSubmitCommand : public cmCTestHandlerCommand
{
public:
- cmCTestSubmitCommand()
- {
- this->PartsMentioned = false;
- this->FilesMentioned = false;
- this->InternalTest = false;
- this->RetryCount = "";
- this->RetryDelay = "";
- this->CDashUpload = false;
- }
-
- /**
- * This is a virtual constructor for the command.
- */
- cmCommand* Clone() override
- {
- cmCTestSubmitCommand* ni = new cmCTestSubmitCommand;
- ni->CTest = this->CTest;
- ni->CTestScriptHandler = this->CTestScriptHandler;
- return ni;
- }
+ cmCTestSubmitCommand();
+ cmCommand* Clone() override;
bool InitialPass(std::vector<std::string> const& args,
cmExecutionStatus& status) override;
@@ -75,11 +57,17 @@ protected:
ArgumentDoingLast2
};
+ enum
+ {
+ cts_BUILD_ID = ct_LAST,
+ cts_LAST
+ };
+
bool PartsMentioned;
std::set<cmCTest::Part> Parts;
bool FilesMentioned;
bool InternalTest;
- cmCTest::SetOfStrings Files;
+ std::set<std::string> Files;
std::string RetryCount;
std::string RetryDelay;
bool CDashUpload;
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index 87112da9e..1fa7988b7 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -63,7 +63,7 @@ private:
void CharacterDataHandler(const char* data, int length) override
{
- this->CurrentValue.insert(this->CurrentValue.end(), data, data + length);
+ cmAppend(this->CurrentValue, data, data + length);
}
void EndElement(const std::string& name) override
@@ -93,12 +93,9 @@ static size_t cmCTestSubmitHandlerWriteMemoryCallback(void* ptr, size_t size,
size_t nmemb, void* data)
{
int realsize = static_cast<int>(size * nmemb);
-
- cmCTestSubmitHandlerVectorOfChar* vec =
- static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
const char* chPtr = static_cast<char*>(ptr);
- vec->insert(vec->end(), chPtr, chPtr + realsize);
-
+ cmAppend(*static_cast<cmCTestSubmitHandlerVectorOfChar*>(data), chPtr,
+ chPtr + realsize);
return realsize;
}
@@ -107,10 +104,8 @@ static size_t cmCTestSubmitHandlerCurlDebugCallback(CURL* /*unused*/,
char* chPtr, size_t size,
void* data)
{
- cmCTestSubmitHandlerVectorOfChar* vec =
- static_cast<cmCTestSubmitHandlerVectorOfChar*>(data);
- vec->insert(vec->end(), chPtr, chPtr + size);
-
+ cmAppend(*static_cast<cmCTestSubmitHandlerVectorOfChar*>(data), chPtr,
+ chPtr + size);
return size;
}
@@ -259,8 +254,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
upload_as += ctest_curl.Escape(this->CTest->GetCurrentTag());
upload_as += "-";
upload_as += ctest_curl.Escape(this->CTest->GetTestModelString());
- cmCTestScriptHandler* ch = static_cast<cmCTestScriptHandler*>(
- this->CTest->GetHandler("script"));
+ cmCTestScriptHandler* ch = this->CTest->GetScriptHandler();
cmake* cm = ch->GetCMake();
if (cm) {
const char* subproject =
@@ -343,7 +337,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
if (!chunk.empty()) {
cmCTestOptionalLog(this->CTest, DEBUG,
"CURL output: ["
- << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+ << cmCTestLogWrite(chunk.data(), chunk.size())
<< "]" << std::endl,
this->Quiet);
this->ParseResponse(chunk);
@@ -352,7 +346,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
cmCTestOptionalLog(
this->CTest, DEBUG,
"CURL debug output: ["
- << cmCTestLogWrite(&*chunkDebug.begin(), chunkDebug.size()) << "]"
+ << cmCTestLogWrite(chunkDebug.data(), chunkDebug.size()) << "]"
<< std::endl,
this->Quiet);
}
@@ -404,12 +398,11 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
res = ::curl_easy_perform(curl);
if (!chunk.empty()) {
- cmCTestOptionalLog(
- this->CTest, DEBUG,
- "CURL output: ["
- << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
- << std::endl,
- this->Quiet);
+ cmCTestOptionalLog(this->CTest, DEBUG,
+ "CURL output: ["
+ << cmCTestLogWrite(chunk.data(), chunk.size())
+ << "]" << std::endl,
+ this->Quiet);
this->ParseResponse(chunk);
}
@@ -433,11 +426,11 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
// avoid deref of begin for zero size array
if (!chunk.empty()) {
*this->LogFile << " Curl output was: "
- << cmCTestLogWrite(&*chunk.begin(), chunk.size())
+ << cmCTestLogWrite(chunk.data(), chunk.size())
<< std::endl;
cmCTestLog(this->CTest, ERROR_MESSAGE,
"CURL output: ["
- << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "]"
+ << cmCTestLogWrite(chunk.data(), chunk.size()) << "]"
<< std::endl);
}
::curl_easy_cleanup(curl);
@@ -486,7 +479,7 @@ void cmCTestSubmitHandler::ParseResponse(
if (this->HasWarnings || this->HasErrors) {
cmCTestLog(this->CTest, HANDLER_OUTPUT,
" Server Response:\n"
- << cmCTestLogWrite(&*chunk.begin(), chunk.size()) << "\n");
+ << cmCTestLogWrite(chunk.data(), chunk.size()) << "\n");
}
}
@@ -559,8 +552,7 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file,
// has already been uploaded
// TODO I added support for subproject. You would need to add
// a "&subproject=subprojectname" to the first POST.
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(this->CTest->GetHandler("script"));
+ cmCTestScriptHandler* ch = this->CTest->GetScriptHandler();
cmake* cm = ch->GetCMake();
const char* subproject = cm->GetState()->GetGlobalProperty("SubProject");
// TODO: Encode values for a URL instead of trusting caller.
@@ -772,8 +764,7 @@ int cmCTestSubmitHandler::ProcessHandler()
if (!this->Files.empty()) {
// Submit the explicitly selected files:
- //
- files.insert(files.end(), this->Files.begin(), this->Files.end());
+ cmAppend(files, this->Files);
}
// Add to the list of files to submit from any selected, existing parts:
@@ -819,8 +810,7 @@ int cmCTestSubmitHandler::ProcessHandler()
}
// Submit files from this part.
- std::vector<std::string> const& pfiles = this->CTest->GetSubmitFiles(p);
- files.insert(files.end(), pfiles.begin(), pfiles.end());
+ cmAppend(files, this->CTest->GetSubmitFiles(p));
}
// Make sure files are unique, but preserve order.
@@ -903,7 +893,7 @@ void cmCTestSubmitHandler::SelectParts(std::set<cmCTest::Part> const& parts)
}
}
-void cmCTestSubmitHandler::SelectFiles(cmCTest::SetOfStrings const& files)
+void cmCTestSubmitHandler::SelectFiles(std::set<std::string> const& files)
{
this->Files.insert(files.begin(), files.end());
}
diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h
index 58f4f975d..e0fed10e0 100644
--- a/Source/CTest/cmCTestSubmitHandler.h
+++ b/Source/CTest/cmCTestSubmitHandler.h
@@ -38,7 +38,7 @@ public:
void SelectParts(std::set<cmCTest::Part> const& parts);
/** Specify a set of files to submit. */
- void SelectFiles(cmCTest::SetOfStrings const& files);
+ void SelectFiles(std::set<std::string> const& files);
// handle the cdash file upload protocol
int HandleCDashUploadFile(std::string const& file, std::string const& type);
@@ -74,7 +74,7 @@ private:
bool SubmitPart[cmCTest::PartCount];
bool HasWarnings;
bool HasErrors;
- cmCTest::SetOfStrings Files;
+ std::set<std::string> Files;
std::vector<std::string> HttpHeaders;
};
diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx
index 895ca1267..cfd5e3dd2 100644
--- a/Source/CTest/cmCTestTestCommand.cxx
+++ b/Source/CTest/cmCTestTestCommand.cxx
@@ -4,6 +4,7 @@
#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
+#include "cmCTestTestHandler.h"
#include "cmDuration.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
@@ -140,5 +141,7 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
cmCTestGenericHandler* cmCTestTestCommand::InitializeActualHandler()
{
- return this->CTest->GetInitializedHandler("test");
+ cmCTestTestHandler* handler = this->CTest->GetTestHandler();
+ handler->Initialize();
+ return handler;
}
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index cf2652afe..0ed56c850 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -1486,7 +1486,7 @@ int cmCTestTestHandler::ExecuteCommands(std::vector<std::string>& vec)
int retVal = 0;
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Run command: " << it << std::endl, this->Quiet);
- if (!cmSystemTools::RunSingleCommand(it.c_str(), nullptr, nullptr, &retVal,
+ if (!cmSystemTools::RunSingleCommand(it, nullptr, nullptr, &retVal,
nullptr, cmSystemTools::OUTPUT_MERGE
/*this->Verbose*/) ||
retVal != 0) {
@@ -2265,8 +2265,8 @@ bool cmCTestTestHandler::SetTestsProperties(
size_t pos = val.find_first_of('=');
if (pos != std::string::npos) {
std::string mKey = val.substr(0, pos);
- const char* mVal = val.c_str() + pos + 1;
- rt.Measurements[mKey] = mVal;
+ std::string mVal = val.substr(pos + 1);
+ rt.Measurements[mKey] = std::move(mVal);
} else {
rt.Measurements[val] = "1";
}
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index 0b557dbcb..7f3f5e4f8 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -11,6 +11,7 @@
#include "cmsys/RegularExpression.hxx"
#include <chrono>
+#include <cstdint>
#include <iosfwd>
#include <map>
#include <set>
@@ -58,7 +59,7 @@ public:
*/
void PopulateCustomVectors(cmMakefile* mf) override;
- ///! Control the use of the regular expresisons, call these methods to turn
+ //! Control the use of the regular expresisons, call these methods to turn
/// them on
void UseIncludeRegExp();
void UseExcludeRegExp();
@@ -77,7 +78,7 @@ public:
this->CustomMaximumFailedTestOutputSize = n;
}
- ///! pass the -I argument down
+ //! pass the -I argument down
void SetTestsToRunInformation(const char*);
cmCTestTestHandler();
@@ -153,7 +154,7 @@ public:
std::string Reason;
std::string FullCommandLine;
cmDuration ExecutionTime;
- int ReturnValue;
+ std::int64_t ReturnValue;
int Status;
std::string ExceptionStatus;
bool CompressOutput;
diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx
index 3d800f8b3..65dc9211a 100644
--- a/Source/CTest/cmCTestUpdateCommand.cxx
+++ b/Source/CTest/cmCTestUpdateCommand.cxx
@@ -3,7 +3,7 @@
#include "cmCTestUpdateCommand.h"
#include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
+#include "cmCTestUpdateHandler.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
@@ -62,6 +62,9 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler()
this->Makefile, "UpdateVersionOnly", "CTEST_UPDATE_VERSION_ONLY",
this->Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
+ this->Makefile, "UpdateVersionOverride", "CTEST_UPDATE_VERSION_OVERRIDE",
+ this->Quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
this->Makefile, "HGCommand", "CTEST_HG_COMMAND", this->Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
this->Makefile, "HGUpdateOptions", "CTEST_HG_UPDATE_OPTIONS", this->Quiet);
@@ -74,12 +77,8 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler()
this->CTest->SetCTestConfigurationFromCMakeVariable(
this->Makefile, "P4Options", "CTEST_P4_OPTIONS", this->Quiet);
- cmCTestGenericHandler* handler =
- this->CTest->GetInitializedHandler("update");
- if (!handler) {
- this->SetError("internal CTest error. Cannot instantiate update handler");
- return nullptr;
- }
+ cmCTestUpdateHandler* handler = this->CTest->GetUpdateHandler();
+ handler->Initialize();
handler->SetCommand(this);
if (source_dir.empty()) {
this->SetError("source directory not specified. Please use SOURCE tag");
diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx
index e3b7e9ef3..5cfc4a7cd 100644
--- a/Source/CTest/cmCTestUpdateHandler.cxx
+++ b/Source/CTest/cmCTestUpdateHandler.cxx
@@ -199,6 +199,10 @@ int cmCTestUpdateHandler::ProcessHandler()
xml.Element("UpdateCommand", vc->GetUpdateCommandLine());
xml.Element("UpdateType",
cmCTestUpdateHandlerUpdateToString(this->UpdateType));
+ std::string changeId = this->CTest->GetCTestConfiguration("ChangeId");
+ if (!changeId.empty()) {
+ xml.Element("ChangeId", changeId);
+ }
bool loadedMods = vc->WriteXML(xml);
diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx
index 2fe2cd347..59fbf371c 100644
--- a/Source/CTest/cmCTestUploadCommand.cxx
+++ b/Source/CTest/cmCTestUploadCommand.cxx
@@ -6,7 +6,6 @@
#include <vector>
#include "cmCTest.h"
-#include "cmCTestGenericHandler.h"
#include "cmCTestUploadHandler.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
@@ -14,14 +13,9 @@
cmCTestGenericHandler* cmCTestUploadCommand::InitializeHandler()
{
- cmCTestGenericHandler* handler =
- this->CTest->GetInitializedHandler("upload");
- if (!handler) {
- this->SetError("internal CTest error. Cannot instantiate upload handler");
- return nullptr;
- }
- static_cast<cmCTestUploadHandler*>(handler)->SetFiles(this->Files);
-
+ cmCTestUploadHandler* handler = this->CTest->GetUploadHandler();
+ handler->Initialize();
+ handler->SetFiles(this->Files);
handler->SetQuiet(this->Quiet);
return handler;
}
diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h
index 61bf1cc58..0d3b06e43 100644
--- a/Source/CTest/cmCTestUploadCommand.h
+++ b/Source/CTest/cmCTestUploadCommand.h
@@ -5,9 +5,9 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include "cmCTest.h"
#include "cmCTestHandlerCommand.h"
+#include <set>
#include <string>
class cmCTestGenericHandler;
@@ -22,8 +22,6 @@ class cmCommand;
class cmCTestUploadCommand : public cmCTestHandlerCommand
{
public:
- cmCTestUploadCommand() {}
-
/**
* This is a virtual constructor for the command.
*/
@@ -55,7 +53,7 @@ protected:
ArgumentDoingLast2
};
- cmCTest::SetOfStrings Files;
+ std::set<std::string> Files;
};
#endif
diff --git a/Source/CTest/cmCTestUploadHandler.cxx b/Source/CTest/cmCTestUploadHandler.cxx
index 261ecab9a..9efdf70b8 100644
--- a/Source/CTest/cmCTestUploadHandler.cxx
+++ b/Source/CTest/cmCTestUploadHandler.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestUploadHandler.h"
+#include "cmCTest.h"
#include "cmGeneratedFileStream.h"
#include "cmVersion.h"
#include "cmXMLWriter.h"
@@ -20,7 +21,7 @@ void cmCTestUploadHandler::Initialize()
this->Files.clear();
}
-void cmCTestUploadHandler::SetFiles(const cmCTest::SetOfStrings& files)
+void cmCTestUploadHandler::SetFiles(std::set<std::string> const& files)
{
this->Files = files;
}
@@ -50,7 +51,7 @@ int cmCTestUploadHandler::ProcessHandler()
this->CTest->GetTestModelString());
xml.Attribute("Name", this->CTest->GetCTestConfiguration("Site"));
xml.Attribute("Generator",
- std::string("ctest") + cmVersion::GetCMakeVersion());
+ std::string("ctest-") + cmVersion::GetCMakeVersion());
this->CTest->AddSiteProperties(xml);
xml.StartElement("Upload");
diff --git a/Source/CTest/cmCTestUploadHandler.h b/Source/CTest/cmCTestUploadHandler.h
index ff5057418..4d8fab487 100644
--- a/Source/CTest/cmCTestUploadHandler.h
+++ b/Source/CTest/cmCTestUploadHandler.h
@@ -5,9 +5,11 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
+#include <set>
+#include <string>
+
/** \class cmCTestUploadHandler
* \brief Helper class for CTest
*
@@ -20,7 +22,6 @@ public:
typedef cmCTestGenericHandler Superclass;
cmCTestUploadHandler();
- ~cmCTestUploadHandler() override {}
/*
* The main entry point for this class
@@ -30,10 +31,10 @@ public:
void Initialize() override;
/** Specify a set of files to submit. */
- void SetFiles(cmCTest::SetOfStrings const& files);
+ void SetFiles(std::set<std::string> const& files);
private:
- cmCTest::SetOfStrings Files;
+ std::set<std::string> Files;
};
#endif
diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx
index 374e73ffb..eea41cf74 100644
--- a/Source/CTest/cmCTestVC.cxx
+++ b/Source/CTest/cmCTestVC.cxx
@@ -141,6 +141,15 @@ void cmCTestVC::CleanupImpl()
bool cmCTestVC::Update()
{
bool result = true;
+
+ // Use the explicitly specified version.
+ std::string versionOverride =
+ this->CTest->GetCTestConfiguration("UpdateVersionOverride");
+ if (!versionOverride.empty()) {
+ this->SetNewRevision(versionOverride);
+ return true;
+ }
+
// if update version only is on then do not actually update,
// just note the current version and finish
if (!cmSystemTools::IsOn(
@@ -166,6 +175,11 @@ bool cmCTestVC::NoteNewRevision()
return true;
}
+void cmCTestVC::SetNewRevision(std::string const& /*unused*/)
+{
+ // We do nothing by default.
+}
+
bool cmCTestVC::UpdateImpl()
{
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
diff --git a/Source/CTest/cmCTestVC.h b/Source/CTest/cmCTestVC.h
index 69a3bf023..2a4765d28 100644
--- a/Source/CTest/cmCTestVC.h
+++ b/Source/CTest/cmCTestVC.h
@@ -70,6 +70,7 @@ protected:
virtual bool NoteOldRevision();
virtual bool UpdateImpl();
virtual bool NoteNewRevision();
+ virtual void SetNewRevision(std::string const& revision);
virtual bool WriteXMLUpdates(cmXMLWriter& xml);
#if defined(__SUNPRO_CC) && __SUNPRO_CC <= 0x510
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index 70ef8dfcd..7a3b82e61 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -2,62 +2,23 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmProcess.h"
+#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCTestRunTest.h"
#include "cmCTestTestHandler.h"
+#include "cmGetPipes.h"
#include "cmsys/Process.h"
-#include <fcntl.h>
#include <iostream>
#include <signal.h>
#include <string>
-#if !defined(_WIN32)
-# include <unistd.h>
+#if defined(_WIN32)
+# include "cm_kwiml.h"
#endif
#include <utility>
#define CM_PROCESS_BUF_SIZE 65536
-#if defined(_WIN32) && !defined(__CYGWIN__)
-# include <io.h>
-
-static int cmProcessGetPipes(int* fds)
-{
- SECURITY_ATTRIBUTES attr;
- HANDLE readh, writeh;
- attr.nLength = sizeof(attr);
- attr.lpSecurityDescriptor = nullptr;
- attr.bInheritHandle = FALSE;
- if (!CreatePipe(&readh, &writeh, &attr, 0))
- return uv_translate_sys_error(GetLastError());
- fds[0] = _open_osfhandle((intptr_t)readh, 0);
- fds[1] = _open_osfhandle((intptr_t)writeh, 0);
- if (fds[0] == -1 || fds[1] == -1) {
- CloseHandle(readh);
- CloseHandle(writeh);
- return uv_translate_sys_error(GetLastError());
- }
- return 0;
-}
-#else
-# include <errno.h>
-
-static int cmProcessGetPipes(int* fds)
-{
- if (pipe(fds) == -1) {
- return uv_translate_sys_error(errno);
- }
-
- if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
- fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
- close(fds[0]);
- close(fds[1]);
- return uv_translate_sys_error(errno);
- }
- return 0;
-}
-#endif
-
cmProcess::cmProcess(cmCTestRunTest& runner)
: Runner(runner)
, Conv(cmProcessOutput::UTF8, CM_PROCESS_BUF_SIZE)
@@ -71,7 +32,7 @@ cmProcess::cmProcess(cmCTestRunTest& runner)
cmProcess::~cmProcess() = default;
-void cmProcess::SetCommand(const char* command)
+void cmProcess::SetCommand(std::string const& command)
{
this->Command = command;
}
@@ -81,6 +42,11 @@ void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
this->Arguments = args;
}
+void cmProcess::SetWorkingDirectory(std::string const& dir)
+{
+ this->WorkingDirectory = dir;
+}
+
bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity)
{
this->ProcessState = cmProcess::State::Error;
@@ -113,7 +79,7 @@ bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity)
pipe_reader.init(loop, 0, this);
int fds[2] = { -1, -1 };
- status = cmProcessGetPipes(fds);
+ status = cmGetPipes(fds);
if (status != 0) {
cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
"Error initializing pipe: " << uv_strerror(status)
@@ -199,7 +165,7 @@ bool cmProcess::Buffer::GetLine(std::string& line)
for (size_type sz = this->size(); this->Last != sz; ++this->Last) {
if ((*this)[this->Last] == '\n' || (*this)[this->Last] == '\0') {
// Extract the range first..last as a line.
- const char* text = &*this->begin() + this->First;
+ const char* text = this->data() + this->First;
size_type length = this->Last - this->First;
while (length && text[length - 1] == '\r') {
length--;
@@ -229,7 +195,7 @@ bool cmProcess::Buffer::GetLast(std::string& line)
{
// Return the partial last line, if any.
if (!this->empty()) {
- line.assign(&*this->begin(), this->size());
+ line.assign(this->data(), this->size());
this->First = this->Last = 0;
this->clear();
return true;
@@ -250,7 +216,7 @@ void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf)
if (nread > 0) {
std::string strdata;
this->Conv.DecodeText(buf->base, static_cast<size_t>(nread), strdata);
- this->Output.insert(this->Output.end(), strdata.begin(), strdata.end());
+ cmAppend(this->Output, strdata);
while (this->Output.GetLine(line)) {
this->Runner.CheckOutput(line);
@@ -353,7 +319,7 @@ void cmProcess::OnExit(int64_t exit_status, int term_signal)
}
// Record exit information.
- this->ExitValue = static_cast<int>(exit_status);
+ this->ExitValue = exit_status;
this->Signal = term_signal;
this->TotalTime = std::chrono::steady_clock::now() - this->StartTime;
// Because of a processor clock scew the runtime may become slightly
@@ -539,7 +505,8 @@ std::string cmProcess::GetExitExceptionString()
case STATUS_NO_MEMORY:
default:
char buf[1024];
- _snprintf(buf, 1024, "Exit code 0x%x\n", this->ExitValue);
+ const char* fmt = "Exit code 0x%" KWIML_INT_PRIx64 "\n";
+ _snprintf(buf, 1024, fmt, this->ExitValue);
exception_str.assign(buf);
}
#else
diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h
index b2d87fab3..a0a4b6b20 100644
--- a/Source/CTest/cmProcess.h
+++ b/Source/CTest/cmProcess.h
@@ -28,10 +28,9 @@ class cmProcess
public:
explicit cmProcess(cmCTestRunTest& runner);
~cmProcess();
- const char* GetCommand() { return this->Command.c_str(); }
- void SetCommand(const char* command);
+ void SetCommand(std::string const& command);
void SetCommandArguments(std::vector<std::string> const& arg);
- void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; }
+ void SetWorkingDirectory(std::string const& dir);
void SetTimeout(cmDuration t) { this->Timeout = t; }
void ChangeTimeout(cmDuration t);
void ResetStartTime();
@@ -53,7 +52,7 @@ public:
State GetProcessStatus();
int GetId() { return this->Id; }
void SetId(int id) { this->Id = id; }
- int GetExitValue() { return this->ExitValue; }
+ int64_t GetExitValue() { return this->ExitValue; }
cmDuration GetTotalTime() { return this->TotalTime; }
enum class Exception
@@ -122,7 +121,7 @@ private:
std::vector<std::string> Arguments;
std::vector<const char*> ProcessArgs;
int Id;
- int ExitValue;
+ int64_t ExitValue;
};
#endif
diff --git a/Source/Checks/cm_cxx17_check.cpp b/Source/Checks/cm_cxx17_check.cpp
index 9ea52c456..593d9b263 100644
--- a/Source/Checks/cm_cxx17_check.cpp
+++ b/Source/Checks/cm_cxx17_check.cpp
@@ -3,6 +3,10 @@
#include <memory>
#include <unordered_map>
+#ifdef _MSC_VER
+# include <comdef.h>
+#endif
+
int main()
{
int a[] = { 0, 1, 2 };
@@ -14,5 +18,14 @@ int main()
auto ci = std::size(a);
std::unique_ptr<int> u(new int(0));
+
+#ifdef _MSC_VER
+ // clang-cl has problems instantiating this constructor in C++17 mode
+ // error: indirection requires pointer operand ('const _GUID' invalid)
+ // return *_IID;
+ IUnknownPtr ptr{};
+ IDispatchPtr disp(ptr);
+#endif
+
return *u + *ai + *(bi - 1) + (3 - static_cast<int>(ci));
}
diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
index f2982a62c..7caed0cd5 100644
--- a/Source/CursesDialog/ccmake.cxx
+++ b/Source/CursesDialog/ccmake.cxx
@@ -67,6 +67,7 @@ void onsig(int /*unused*/)
int main(int argc, char const* const* argv)
{
+ cmSystemTools::EnsureStdPipes();
cmsys::Encoding::CommandLineArguments encoding_args =
cmsys::Encoding::CommandLineArguments::Main(argc, argv);
argc = encoding_args.argc();
@@ -150,7 +151,7 @@ int main(int argc, char const* const* argv)
}
cmSystemTools::SetMessageCallback(
- [myform](const char* message, const char* title) {
+ [myform](const std::string& message, const char* title) {
myform->AddError(message, title);
});
diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
index e7ed09717..c1dd591e0 100644
--- a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
+++ b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
@@ -83,7 +83,7 @@ cmCursesCacheEntryComposite::cmCursesCacheEntryComposite(
break;
}
case cmStateEnums::UNINITIALIZED:
- cmSystemTools::Error("Found an undefined variable: ", key.c_str());
+ cmSystemTools::Error("Found an undefined variable: " + key);
break;
default:
// TODO : put warning message here
diff --git a/Source/CursesDialog/cmCursesForm.h b/Source/CursesDialog/cmCursesForm.h
index ddb67deeb..78429059e 100644
--- a/Source/CursesDialog/cmCursesForm.h
+++ b/Source/CursesDialog/cmCursesForm.h
@@ -9,6 +9,8 @@
#include "cmsys/FStream.hxx"
+#include <string>
+
class cmCursesForm
{
public:
@@ -34,7 +36,7 @@ public:
// Description:
// During a CMake run, an error handle should add errors
// to be displayed afterwards.
- virtual void AddError(const char*, const char*) {}
+ virtual void AddError(const std::string&, const char*) {}
// Description:
// Turn debugging on. This will create ccmakelog.txt.
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx
index a41d051b1..4e887d68f 100644
--- a/Source/CursesDialog/cmCursesLongMessageForm.cxx
+++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx
@@ -19,9 +19,8 @@ cmCursesLongMessageForm::cmCursesLongMessageForm(
std::vector<std::string> const& messages, const char* title)
{
// Append all messages into on big string
- std::vector<std::string>::const_iterator it;
- for (it = messages.begin(); it != messages.end(); it++) {
- this->Messages += (*it);
+ for (std::string const& message : messages) {
+ this->Messages += message;
// Add one blank line after each message
this->Messages += "\n\n";
}
diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx
index 8ca7802f1..028e85298 100644
--- a/Source/CursesDialog/cmCursesMainForm.cxx
+++ b/Source/CursesDialog/cmCursesMainForm.cxx
@@ -79,18 +79,11 @@ cmCursesMainForm::~cmCursesMainForm()
// See if a cache entry is in the list of entries in the ui.
bool cmCursesMainForm::LookForCacheEntry(const std::string& key)
{
- if (!this->Entries) {
- return false;
- }
-
- std::vector<cmCursesCacheEntryComposite*>::iterator it;
- for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
- if (key == (*it)->Key) {
- return true;
- }
- }
-
- return false;
+ return this->Entries &&
+ std::any_of(this->Entries->begin(), this->Entries->end(),
+ [&key](cmCursesCacheEntryComposite* entry) {
+ return key == entry->Key;
+ });
}
// Create new cmCursesCacheEntryComposite entries from the cache
@@ -107,10 +100,9 @@ void cmCursesMainForm::InitializeUI()
// Count non-internal and non-static entries
int count = 0;
- for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
- it != cacheKeys.end(); ++it) {
+ for (std::string const& key : cacheKeys) {
cmStateEnums::CacheEntryType t =
- this->CMakeInstance->GetState()->GetCacheEntryType(*it);
+ this->CMakeInstance->GetState()->GetCacheEntryType(key);
if (t != cmStateEnums::INTERNAL && t != cmStateEnums::STATIC &&
t != cmStateEnums::UNINITIALIZED) {
++count;
@@ -130,11 +122,9 @@ void cmCursesMainForm::InitializeUI()
// Create the composites.
// First add entries which are new
- for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
- it != cacheKeys.end(); ++it) {
- std::string key = *it;
+ for (std::string const& key : cacheKeys) {
cmStateEnums::CacheEntryType t =
- this->CMakeInstance->GetState()->GetCacheEntryType(*it);
+ this->CMakeInstance->GetState()->GetCacheEntryType(key);
if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC ||
t == cmStateEnums::UNINITIALIZED) {
continue;
@@ -148,11 +138,9 @@ void cmCursesMainForm::InitializeUI()
}
// then add entries which are old
- for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
- it != cacheKeys.end(); ++it) {
- std::string key = *it;
+ for (std::string const& key : cacheKeys) {
cmStateEnums::CacheEntryType t =
- this->CMakeInstance->GetState()->GetCacheEntryType(*it);
+ this->CMakeInstance->GetState()->GetCacheEntryType(key);
if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC ||
t == cmStateEnums::UNINITIALIZED) {
continue;
@@ -190,13 +178,12 @@ void cmCursesMainForm::RePost()
} else {
// If normal mode, count only non-advanced entries
this->NumberOfVisibleEntries = 0;
- std::vector<cmCursesCacheEntryComposite*>::iterator it;
- for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+ for (cmCursesCacheEntryComposite* entry : *this->Entries) {
const char* existingValue =
- this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+ this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
bool advanced =
this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
- (*it)->GetValue(), "ADVANCED");
+ entry->GetValue(), "ADVANCED");
if (!existingValue || (!this->AdvancedMode && advanced)) {
continue;
}
@@ -217,27 +204,26 @@ void cmCursesMainForm::RePost()
// Assign fields
int j = 0;
- std::vector<cmCursesCacheEntryComposite*>::iterator it;
- for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+ for (cmCursesCacheEntryComposite* entry : *this->Entries) {
const char* existingValue =
- this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+ this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
bool advanced =
this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
- (*it)->GetValue(), "ADVANCED");
+ entry->GetValue(), "ADVANCED");
if (!existingValue || (!this->AdvancedMode && advanced)) {
continue;
}
- this->Fields[3 * j] = (*it)->Label->Field;
- this->Fields[3 * j + 1] = (*it)->IsNewLabel->Field;
- this->Fields[3 * j + 2] = (*it)->Entry->Field;
+ this->Fields[3 * j] = entry->Label->Field;
+ this->Fields[3 * j + 1] = entry->IsNewLabel->Field;
+ this->Fields[3 * j + 2] = entry->Entry->Field;
j++;
}
// if no cache entries there should still be one dummy field
if (j == 0) {
- it = this->Entries->begin();
- this->Fields[0] = (*it)->Label->Field;
- this->Fields[1] = (*it)->IsNewLabel->Field;
- this->Fields[2] = (*it)->Entry->Field;
+ const auto& front = *this->Entries->front();
+ this->Fields[0] = front.Label->Field;
+ this->Fields[1] = front.IsNewLabel->Field;
+ this->Fields[2] = front.Entry->Field;
this->NumberOfVisibleEntries = 1;
}
// Has to be null terminated.
@@ -278,13 +264,12 @@ void cmCursesMainForm::Render(int left, int top, int width, int height)
} else {
// If normal, display only non-advanced entries
this->NumberOfVisibleEntries = 0;
- std::vector<cmCursesCacheEntryComposite*>::iterator it;
- for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+ for (cmCursesCacheEntryComposite* entry : *this->Entries) {
const char* existingValue =
- this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+ this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
bool advanced =
this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
- (*it)->GetValue(), "ADVANCED");
+ entry->GetValue(), "ADVANCED");
if (!existingValue || (!this->AdvancedMode && advanced)) {
continue;
}
@@ -297,13 +282,12 @@ void cmCursesMainForm::Render(int left, int top, int width, int height)
if (height > 0) {
bool isNewPage;
int i = 0;
- std::vector<cmCursesCacheEntryComposite*>::iterator it;
- for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
+ for (cmCursesCacheEntryComposite* entry : *this->Entries) {
const char* existingValue =
- this->CMakeInstance->GetState()->GetCacheEntryValue((*it)->GetValue());
+ this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue());
bool advanced =
this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool(
- (*it)->GetValue(), "ADVANCED");
+ entry->GetValue(), "ADVANCED");
if (!existingValue || (!this->AdvancedMode && advanced)) {
continue;
}
@@ -314,10 +298,10 @@ void cmCursesMainForm::Render(int left, int top, int width, int height)
if (isNewPage) {
this->NumberOfPages++;
}
- (*it)->Label->Move(left, top + row - 1, isNewPage);
- (*it)->IsNewLabel->Move(left + 32, top + row - 1, false);
- (*it)->Entry->Move(left + 33, top + row - 1, false);
- (*it)->Entry->SetPage(this->NumberOfPages);
+ entry->Label->Move(left, top + row - 1, isNewPage);
+ entry->IsNewLabel->Move(left + 32, top + row - 1, false);
+ entry->Entry->Move(left + 33, top + row - 1, false);
+ entry->Entry->SetPage(this->NumberOfPages);
i++;
}
}
@@ -506,14 +490,14 @@ void cmCursesMainForm::UpdateStatusBar(const char* message)
pos_form_cursor(this->Form);
}
-void cmCursesMainForm::UpdateProgress(const char* msg, float prog)
+void cmCursesMainForm::UpdateProgress(const std::string& msg, float prog)
{
char tmp[1024];
const char* cmsg = tmp;
if (prog >= 0) {
- sprintf(tmp, "%s %i%%", msg, static_cast<int>(100 * prog));
+ sprintf(tmp, "%s %i%%", msg.c_str(), static_cast<int>(100 * prog));
} else {
- cmsg = msg;
+ cmsg = msg.c_str();
}
this->UpdateStatusBar(cmsg);
this->PrintKeys(1);
@@ -533,7 +517,9 @@ int cmCursesMainForm::Configure(int noconfigure)
touchwin(stdscr);
refresh();
this->CMakeInstance->SetProgressCallback(
- [this](const char* msg, float prog) { this->UpdateProgress(msg, prog); });
+ [this](const std::string& msg, float prog) {
+ this->UpdateProgress(msg, prog);
+ });
// always save the current gui values to disk
this->FillCacheManagerFromUI();
@@ -603,7 +589,9 @@ int cmCursesMainForm::Generate()
touchwin(stdscr);
refresh();
this->CMakeInstance->SetProgressCallback(
- [this](const char* msg, float prog) { this->UpdateProgress(msg, prog); });
+ [this](const std::string& msg, float prog) {
+ this->UpdateProgress(msg, prog);
+ });
// Get rid of previous errors
this->Errors = std::vector<std::string>();
@@ -647,7 +635,8 @@ int cmCursesMainForm::Generate()
return 0;
}
-void cmCursesMainForm::AddError(const char* message, const char* /*unused*/)
+void cmCursesMainForm::AddError(const std::string& message,
+ const char* /*unused*/)
{
this->Errors.emplace_back(message);
}
@@ -658,28 +647,29 @@ void cmCursesMainForm::RemoveEntry(const char* value)
return;
}
- std::vector<cmCursesCacheEntryComposite*>::iterator it;
- for (it = this->Entries->begin(); it != this->Entries->end(); ++it) {
- const char* val = (*it)->GetValue();
- if (val && !strcmp(value, val)) {
- this->CMakeInstance->UnwatchUnusedCli(value);
- this->Entries->erase(it);
- break;
- }
+ auto removeIt =
+ std::find_if(this->Entries->begin(), this->Entries->end(),
+ [value](cmCursesCacheEntryComposite* entry) -> bool {
+ const char* val = entry->GetValue();
+ return val != nullptr && !strcmp(value, val);
+ });
+
+ if (removeIt != this->Entries->end()) {
+ this->CMakeInstance->UnwatchUnusedCli(value);
+ this->Entries->erase(removeIt);
}
}
// copy from the list box to the cache manager
void cmCursesMainForm::FillCacheManagerFromUI()
{
- size_t size = this->Entries->size();
- for (size_t i = 0; i < size; i++) {
- std::string cacheKey = (*this->Entries)[i]->Key;
+ for (cmCursesCacheEntryComposite* entry : *this->Entries) {
+ const std::string& cacheKey = entry->Key;
const char* existingValue =
this->CMakeInstance->GetState()->GetCacheEntryValue(cacheKey);
if (existingValue) {
std::string oldValue = existingValue;
- std::string newValue = (*this->Entries)[i]->Entry->GetValue();
+ std::string newValue = entry->Entry->GetValue();
std::string fixedOldValue;
std::string fixedNewValue;
cmStateEnums::CacheEntryType t =
@@ -975,17 +965,14 @@ void cmCursesMainForm::HandleInput()
if (nextCur) {
// make the next or prev. current field after deletion
- nextCur = nullptr;
- std::vector<cmCursesCacheEntryComposite*>::iterator it;
- for (it = this->Entries->begin(); it != this->Entries->end();
- ++it) {
- if (nextVal == (*it)->Key) {
- nextCur = (*it)->Entry->Field;
- }
- }
-
- if (nextCur) {
- set_current_field(this->Form, nextCur);
+ auto nextEntryIt =
+ std::find_if(this->Entries->begin(), this->Entries->end(),
+ [&nextVal](cmCursesCacheEntryComposite* entry) {
+ return nextVal == entry->Key;
+ });
+
+ if (nextEntryIt != this->Entries->end()) {
+ set_current_field(this->Form, (*nextEntryIt)->Entry->Field);
}
}
}
diff --git a/Source/CursesDialog/cmCursesMainForm.h b/Source/CursesDialog/cmCursesMainForm.h
index cc6482fd3..d37997581 100644
--- a/Source/CursesDialog/cmCursesMainForm.h
+++ b/Source/CursesDialog/cmCursesMainForm.h
@@ -81,7 +81,7 @@ public:
* During a CMake run, an error handle should add errors
* to be displayed afterwards.
*/
- void AddError(const char* message, const char* title) override;
+ void AddError(const std::string& message, const char* title) override;
/**
* Used to do a configure. If argument is specified, it does only the check
@@ -102,7 +102,7 @@ public:
/**
* Progress callback
*/
- void UpdateProgress(const char* msg, float prog);
+ void UpdateProgress(const std::string& msg, float prog);
protected:
// Copy the cache values from the user interface to the actual
diff --git a/Source/LexerParser/cmCommandArgumentParser.cxx b/Source/LexerParser/cmCommandArgumentParser.cxx
index 68b9e6c7e..b965b32e8 100644
--- a/Source/LexerParser/cmCommandArgumentParser.cxx
+++ b/Source/LexerParser/cmCommandArgumentParser.cxx
@@ -513,7 +513,7 @@ static const yytype_uint8 yyrline[] =
static const char *const yytname[] =
{
"$end", "error", "$undefined", "cal_ENVCURLY", "cal_NCURLY",
- "cal_DCURLY", "\"$\"", "\"{\"", "\"}\"", "cal_NAME", "\"\\\\\"",
+ "cal_DCURLY", "\"$\"", "\"{\"", "\"}\"", "cal_NAME", R"("\\")",
"cal_SYMBOL", "\"@\"", "cal_ERROR", "cal_ATNAME", "$accept", "Start",
"GoalWithOptionalBackSlash", "Goal", "String", "OuterText", "Variable",
"EnvVarName", "MultipleIds", "ID", YY_NULLPTR
diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt
index 9ce032384..cb89d19fd 100644
--- a/Source/QtDialog/CMakeLists.txt
+++ b/Source/QtDialog/CMakeLists.txt
@@ -2,9 +2,6 @@
# file Copyright.txt or https://cmake.org/licensing for details.
project(QtDialog)
-if(POLICY CMP0020)
- cmake_policy(SET CMP0020 NEW) # Drop when CMake >= 2.8.11 required
-endif()
CMake_OPTIONAL_COMPONENT(cmake-gui)
find_package(Qt5Widgets QUIET)
if (Qt5Widgets_FOUND)
diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx
index 8d9a50ce3..c9ebba83a 100644
--- a/Source/QtDialog/CMakeSetup.cxx
+++ b/Source/QtDialog/CMakeSetup.cxx
@@ -55,6 +55,7 @@ Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin);
int main(int argc, char** argv)
{
+ cmSystemTools::EnsureStdPipes();
cmsys::Encoding::CommandLineArguments encoding_args =
cmsys::Encoding::CommandLineArguments::Main(argc, argv);
int argc2 = encoding_args.argc();
diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx
index 5f6ccca4b..e98cdcf4a 100644
--- a/Source/QtDialog/CMakeSetupDialog.cxx
+++ b/Source/QtDialog/CMakeSetupDialog.cxx
@@ -862,7 +862,7 @@ void CMakeSetupDialog::doAbout()
"built using Qt %2 (qt-project.org).\n"
#ifdef USE_LGPL
"\n"
- "The Qt Toolkit is Copyright (C) Digia Plc and/or its subsidiary(-ies).\n"
+ "The Qt Toolkit is Copyright (C) The Qt Company Ltd.\n"
"Qt is licensed under terms of the GNU LGPLv" USE_LGPL ", available at:\n"
" \"%3\""
#endif
diff --git a/Source/QtDialog/FirstConfigure.cxx b/Source/QtDialog/FirstConfigure.cxx
index f28e1a821..364a378b3 100644
--- a/Source/QtDialog/FirstConfigure.cxx
+++ b/Source/QtDialog/FirstConfigure.cxx
@@ -95,33 +95,32 @@ void StartCompilerSetup::setGenerators(
QStringList generator_list;
- std::vector<cmake::GeneratorInfo>::const_iterator it;
- for (it = gens.begin(); it != gens.end(); ++it) {
- generator_list.append(QString::fromLocal8Bit(it->name.c_str()));
+ for (cmake::GeneratorInfo const& gen : gens) {
+ generator_list.append(QString::fromLocal8Bit(gen.name.c_str()));
- if (it->supportsPlatform) {
+ if (gen.supportsPlatform) {
this->GeneratorsSupportingPlatform.append(
- QString::fromLocal8Bit(it->name.c_str()));
+ QString::fromLocal8Bit(gen.name.c_str()));
this
- ->GeneratorDefaultPlatform[QString::fromLocal8Bit(it->name.c_str())] =
- QString::fromLocal8Bit(it->defaultPlatform.c_str());
+ ->GeneratorDefaultPlatform[QString::fromLocal8Bit(gen.name.c_str())] =
+ QString::fromLocal8Bit(gen.defaultPlatform.c_str());
std::vector<std::string>::const_iterator platformIt =
- it->supportedPlatforms.cbegin();
- while (platformIt != it->supportedPlatforms.cend()) {
+ gen.supportedPlatforms.cbegin();
+ while (platformIt != gen.supportedPlatforms.cend()) {
this->GeneratorSupportedPlatforms.insert(
- QString::fromLocal8Bit(it->name.c_str()),
+ QString::fromLocal8Bit(gen.name.c_str()),
QString::fromLocal8Bit((*platformIt).c_str()));
platformIt++;
}
}
- if (it->supportsToolset) {
+ if (gen.supportsToolset) {
this->GeneratorsSupportingToolset.append(
- QString::fromLocal8Bit(it->name.c_str()));
+ QString::fromLocal8Bit(gen.name.c_str()));
}
}
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index a073c3064..f357f9032 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -25,7 +25,7 @@ QCMake::QCMake(QObject* p)
cmSystemTools::SetRunCommandHideConsole(true);
cmSystemTools::SetMessageCallback(
- [this](const char* msg, const char* title) {
+ [this](std::string const& msg, const char* title) {
this->messageCallback(msg, title);
});
cmSystemTools::SetStdoutCallback(
@@ -37,7 +37,7 @@ QCMake::QCMake(QObject* p)
this->CMakeInstance->SetCMakeEditCommand(
cmSystemTools::GetCMakeGUICommand());
this->CMakeInstance->SetProgressCallback(
- [this](const char* msg, float percent) {
+ [this](const std::string& msg, float percent) {
this->progressCallback(msg, percent);
});
@@ -48,9 +48,8 @@ QCMake::QCMake(QObject* p)
this->CMakeInstance->GetRegisteredGenerators(
generators, /*includeNamesWithPlatform=*/false);
- std::vector<cmake::GeneratorInfo>::const_iterator it;
- for (it = generators.begin(); it != generators.end(); ++it) {
- this->AvailableGenerators.push_back(*it);
+ for (cmake::GeneratorInfo const& gen : generators) {
+ this->AvailableGenerators.push_back(gen);
}
}
@@ -234,24 +233,23 @@ void QCMake::setProperties(const QCMakePropertyList& newProps)
// set the value of properties
cmState* state = this->CMakeInstance->GetState();
std::vector<std::string> cacheKeys = state->GetCacheEntryKeys();
- for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
- it != cacheKeys.end(); ++it) {
- cmStateEnums::CacheEntryType t = state->GetCacheEntryType(*it);
+ for (std::string const& key : cacheKeys) {
+ cmStateEnums::CacheEntryType t = state->GetCacheEntryType(key);
if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC) {
continue;
}
QCMakeProperty prop;
- prop.Key = QString::fromLocal8Bit(it->c_str());
+ prop.Key = QString::fromLocal8Bit(key.c_str());
int idx = props.indexOf(prop);
if (idx == -1) {
- toremove.append(QString::fromLocal8Bit(it->c_str()));
+ toremove.append(QString::fromLocal8Bit(key.c_str()));
} else {
prop = props[idx];
if (prop.Value.type() == QVariant::Bool) {
- state->SetCacheEntryValue(*it, prop.Value.toBool() ? "ON" : "OFF");
+ state->SetCacheEntryValue(key, prop.Value.toBool() ? "ON" : "OFF");
} else {
- state->SetCacheEntryValue(*it,
+ state->SetCacheEntryValue(key,
prop.Value.toString().toLocal8Bit().data());
}
props.removeAt(idx);
@@ -297,22 +295,21 @@ QCMakePropertyList QCMake::properties() const
cmState* state = this->CMakeInstance->GetState();
std::vector<std::string> cacheKeys = state->GetCacheEntryKeys();
- for (std::vector<std::string>::const_iterator i = cacheKeys.begin();
- i != cacheKeys.end(); ++i) {
- cmStateEnums::CacheEntryType t = state->GetCacheEntryType(*i);
+ for (std::string const& key : cacheKeys) {
+ cmStateEnums::CacheEntryType t = state->GetCacheEntryType(key);
if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC ||
t == cmStateEnums::UNINITIALIZED) {
continue;
}
- const char* cachedValue = state->GetCacheEntryValue(*i);
+ const char* cachedValue = state->GetCacheEntryValue(key);
QCMakeProperty prop;
- prop.Key = QString::fromLocal8Bit(i->c_str());
+ prop.Key = QString::fromLocal8Bit(key.c_str());
prop.Help =
- QString::fromLocal8Bit(state->GetCacheEntryProperty(*i, "HELPSTRING"));
+ QString::fromLocal8Bit(state->GetCacheEntryProperty(key, "HELPSTRING"));
prop.Value = QString::fromLocal8Bit(cachedValue);
- prop.Advanced = state->GetCacheEntryPropertyAsBool(*i, "ADVANCED");
+ prop.Advanced = state->GetCacheEntryPropertyAsBool(key, "ADVANCED");
if (t == cmStateEnums::BOOL) {
prop.Type = QCMakeProperty::BOOL;
prop.Value = cmSystemTools::IsOn(cachedValue);
@@ -323,7 +320,7 @@ QCMakePropertyList QCMake::properties() const
} else if (t == cmStateEnums::STRING) {
prop.Type = QCMakeProperty::STRING;
const char* stringsProperty =
- state->GetCacheEntryProperty(*i, "STRINGS");
+ state->GetCacheEntryProperty(key, "STRINGS");
if (stringsProperty) {
prop.Strings = QString::fromLocal8Bit(stringsProperty).split(";");
}
@@ -349,19 +346,19 @@ bool QCMake::interruptCallback()
#endif
}
-void QCMake::progressCallback(const char* msg, float percent)
+void QCMake::progressCallback(const std::string& msg, float percent)
{
if (percent >= 0) {
- emit this->progressChanged(QString::fromLocal8Bit(msg), percent);
+ emit this->progressChanged(QString::fromStdString(msg), percent);
} else {
- emit this->outputMessage(QString::fromLocal8Bit(msg));
+ emit this->outputMessage(QString::fromStdString(msg));
}
QCoreApplication::processEvents();
}
-void QCMake::messageCallback(const char* msg, const char* /*title*/)
+void QCMake::messageCallback(std::string const& msg, const char* /*title*/)
{
- emit this->errorMessage(QString::fromLocal8Bit(msg));
+ emit this->errorMessage(QString::fromStdString(msg));
QCoreApplication::processEvents();
}
diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h
index ef4d2a1a1..f2fd6d923 100644
--- a/Source/QtDialog/QCMake.h
+++ b/Source/QtDialog/QCMake.h
@@ -168,8 +168,8 @@ protected:
cmake* CMakeInstance;
bool interruptCallback();
- void progressCallback(const char* msg, float percent);
- void messageCallback(const char* msg, const char* title);
+ void progressCallback(std::string const& msg, float percent);
+ void messageCallback(std::string const& msg, const char* title);
void stdoutCallback(std::string const& msg);
void stderrCallback(std::string const& msg);
diff --git a/Source/QtDialog/RegexExplorer.cxx b/Source/QtDialog/RegexExplorer.cxx
index cb67f85d4..746fd8af2 100644
--- a/Source/QtDialog/RegexExplorer.cxx
+++ b/Source/QtDialog/RegexExplorer.cxx
@@ -20,7 +20,7 @@ void RegexExplorer::setStatusColor(QWidget* widget, bool successful)
QColor color = successful ? QColor(0, 127, 0) : Qt::red;
QPalette palette = widget->palette();
- palette.setColor(QPalette::Foreground, color);
+ palette.setColor(QPalette::WindowText, color);
widget->setPalette(palette);
}
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
index a840f17c1..0be3c85e1 100644
--- a/Source/cmAddCustomCommandCommand.cxx
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -31,7 +31,7 @@ bool cmAddCustomCommandCommand::InitialPass(
return false;
}
- std::string source, target, main_dependency, working, depfile;
+ std::string source, target, main_dependency, working, depfile, job_pool;
std::string comment_buffer;
const char* comment = nullptr;
std::vector<std::string> depends, outputs, output, byproducts;
@@ -65,6 +65,7 @@ bool cmAddCustomCommandCommand::InitialPass(
doing_comment,
doing_working_directory,
doing_depfile,
+ doing_job_pool,
doing_nothing
};
@@ -81,6 +82,7 @@ bool cmAddCustomCommandCommand::InitialPass(
MAKE_STATIC_KEYWORD(DEPENDS);
MAKE_STATIC_KEYWORD(DEPFILE);
MAKE_STATIC_KEYWORD(IMPLICIT_DEPENDS);
+ MAKE_STATIC_KEYWORD(JOB_POOL);
MAKE_STATIC_KEYWORD(MAIN_DEPENDENCY);
MAKE_STATIC_KEYWORD(OUTPUT);
MAKE_STATIC_KEYWORD(OUTPUTS);
@@ -104,6 +106,7 @@ bool cmAddCustomCommandCommand::InitialPass(
keywords.insert(keyDEPENDS);
keywords.insert(keyDEPFILE);
keywords.insert(keyIMPLICIT_DEPENDS);
+ keywords.insert(keyJOB_POOL);
keywords.insert(keyMAIN_DEPENDENCY);
keywords.insert(keyOUTPUT);
keywords.insert(keyOUTPUTS);
@@ -170,6 +173,8 @@ bool cmAddCustomCommandCommand::InitialPass(
this->Makefile->GetGlobalGenerator()->GetName());
return false;
}
+ } else if (copy == keyJOB_POOL) {
+ doing = doing_job_pool;
}
} else {
std::string filename;
@@ -211,6 +216,9 @@ bool cmAddCustomCommandCommand::InitialPass(
case doing_depfile:
depfile = copy;
break;
+ case doing_job_pool:
+ job_pool = copy;
+ break;
case doing_working_directory:
working = copy;
break;
@@ -318,6 +326,11 @@ bool cmAddCustomCommandCommand::InitialPass(
return false;
}
+ if (uses_terminal && !job_pool.empty()) {
+ this->SetError("JOB_POOL is shadowed by USES_TERMINAL.");
+ return false;
+ }
+
// Choose which mode of the command to use.
bool escapeOldStyle = !verbatim;
if (source.empty() && output.empty()) {
@@ -325,14 +338,14 @@ bool cmAddCustomCommandCommand::InitialPass(
std::vector<std::string> no_depends;
this->Makefile->AddCustomCommandToTarget(
target, byproducts, no_depends, commandLines, cctype, comment,
- working.c_str(), escapeOldStyle, uses_terminal, depfile,
+ working.c_str(), escapeOldStyle, uses_terminal, depfile, job_pool,
command_expand_lists);
} else if (target.empty()) {
// Target is empty, use the output.
this->Makefile->AddCustomCommandToOutput(
output, byproducts, depends, main_dependency, commandLines, comment,
working.c_str(), false, escapeOldStyle, uses_terminal,
- command_expand_lists, depfile);
+ command_expand_lists, depfile, job_pool);
// Add implicit dependency scanning requests if any were given.
if (!implicit_depends.empty()) {
diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx
index 8240d3ef2..0ecd5f5a2 100644
--- a/Source/cmAddCustomTargetCommand.cxx
+++ b/Source/cmAddCustomTargetCommand.cxx
@@ -52,6 +52,7 @@ bool cmAddCustomTargetCommand::InitialPass(
std::string comment_buffer;
const char* comment = nullptr;
std::vector<std::string> sources;
+ std::string job_pool;
// Keep track of parser state.
enum tdoing
@@ -62,6 +63,7 @@ bool cmAddCustomTargetCommand::InitialPass(
doing_working_directory,
doing_comment,
doing_source,
+ doing_job_pool,
doing_nothing
};
tdoing doing = doing_command;
@@ -97,6 +99,8 @@ bool cmAddCustomTargetCommand::InitialPass(
command_expand_lists = true;
} else if (copy == "COMMENT") {
doing = doing_comment;
+ } else if (copy == "JOB_POOL") {
+ doing = doing_job_pool;
} else if (copy == "COMMAND") {
doing = doing_command;
@@ -137,6 +141,9 @@ bool cmAddCustomTargetCommand::InitialPass(
case doing_source:
sources.push_back(copy);
break;
+ case doing_job_pool:
+ job_pool = copy;
+ break;
default:
this->SetError("Wrong syntax. Unknown type of argument.");
return false;
@@ -200,12 +207,17 @@ bool cmAddCustomTargetCommand::InitialPass(
return true;
}
+ if (uses_terminal && !job_pool.empty()) {
+ this->SetError("JOB_POOL is shadowed by USES_TERMINAL.");
+ return false;
+ }
+
// Add the utility target to the makefile.
bool escapeOldStyle = !verbatim;
cmTarget* target = this->Makefile->AddUtilityCommand(
targetName, cmMakefile::TargetOrigin::Project, excludeFromAll,
working_directory.c_str(), byproducts, depends, commandLines,
- escapeOldStyle, comment, uses_terminal, command_expand_lists);
+ escapeOldStyle, comment, uses_terminal, command_expand_lists, job_pool);
// Add additional user-specified source files to the target.
target->AddSources(sources);
diff --git a/Source/cmAddDependenciesCommand.cxx b/Source/cmAddDependenciesCommand.cxx
index 021bd2951..4956a471c 100644
--- a/Source/cmAddDependenciesCommand.cxx
+++ b/Source/cmAddDependenciesCommand.cxx
@@ -6,6 +6,7 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmTarget.h"
class cmExecutionStatus;
@@ -27,10 +28,10 @@ bool cmAddDependenciesCommand::InitialPass(
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
}
if (cmTarget* target = this->Makefile->FindTargetToUse(target_name)) {
- std::vector<std::string>::const_iterator s = args.begin();
- ++s; // skip over target_name
- for (; s != args.end(); ++s) {
- target->AddUtility(*s, this->Makefile);
+
+ // skip over target_name
+ for (std::string const& arg : cmMakeRange(args).advance(1)) {
+ target->AddUtility(arg, this->Makefile);
}
} else {
std::ostringstream e;
diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx
index 514933303..ad12e89b9 100644
--- a/Source/cmAddLibraryCommand.cxx
+++ b/Source/cmAddLibraryCommand.cxx
@@ -4,6 +4,7 @@
#include <sstream>
+#include "cmAlgorithms.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
@@ -222,7 +223,9 @@ bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args,
aliasedType != cmStateEnums::STATIC_LIBRARY &&
aliasedType != cmStateEnums::MODULE_LIBRARY &&
aliasedType != cmStateEnums::OBJECT_LIBRARY &&
- aliasedType != cmStateEnums::INTERFACE_LIBRARY) {
+ aliasedType != cmStateEnums::INTERFACE_LIBRARY &&
+ !(aliasedType == cmStateEnums::UNKNOWN_LIBRARY &&
+ aliasedTarget->IsImported())) {
std::ostringstream e;
e << "cannot create ALIAS target \"" << libName << "\" because target \""
<< aliasedName << "\" is not a library.";
@@ -336,7 +339,7 @@ bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args,
return true;
}
- srclists.insert(srclists.end(), s, args.end());
+ cmAppend(srclists, s, args.end());
this->Makefile->AddLibrary(libName, type, srclists, excludeFromAll);
diff --git a/Source/cmAddSubDirectoryCommand.cxx b/Source/cmAddSubDirectoryCommand.cxx
index 75e5aa43f..7947188a5 100644
--- a/Source/cmAddSubDirectoryCommand.cxx
+++ b/Source/cmAddSubDirectoryCommand.cxx
@@ -6,6 +6,7 @@
#include <string.h>
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
class cmExecutionStatus;
@@ -26,15 +27,13 @@ bool cmAddSubDirectoryCommand::InitialPass(
bool excludeFromAll = false;
// process the rest of the arguments looking for optional args
- std::vector<std::string>::const_iterator i = args.begin();
- ++i;
- for (; i != args.end(); ++i) {
- if (*i == "EXCLUDE_FROM_ALL") {
+ for (std::string const& arg : cmMakeRange(args).advance(1)) {
+ if (arg == "EXCLUDE_FROM_ALL") {
excludeFromAll = true;
continue;
}
if (binArg.empty()) {
- binArg = *i;
+ binArg = arg;
} else {
this->SetError("called with incorrect number of arguments");
return false;
diff --git a/Source/cmAddTestCommand.cxx b/Source/cmAddTestCommand.cxx
index 3a3afdb05..bf28702ce 100644
--- a/Source/cmAddTestCommand.cxx
+++ b/Source/cmAddTestCommand.cxx
@@ -27,8 +27,7 @@ bool cmAddTestCommand::InitialPass(std::vector<std::string> const& args,
}
// Collect the command with arguments.
- std::vector<std::string> command;
- command.insert(command.end(), args.begin() + 1, args.end());
+ std::vector<std::string> command(args.begin() + 1, args.end());
// Create the test but add a generator only the first time it is
// seen. This preserves behavior from before test generators.
diff --git a/Source/cmAlgorithms.h b/Source/cmAlgorithms.h
index d38b0d125..d1e32b0d4 100644
--- a/Source/cmAlgorithms.h
+++ b/Source/cmAlgorithms.h
@@ -5,6 +5,8 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cmRange.h"
+
#include "cm_kwiml.h"
#include <algorithm>
#include <functional>
@@ -156,62 +158,29 @@ private:
};
}
-template <typename const_iterator_>
-struct cmRange
-{
- typedef const_iterator_ const_iterator;
- typedef typename std::iterator_traits<const_iterator>::value_type value_type;
- typedef typename std::iterator_traits<const_iterator>::difference_type
- difference_type;
- cmRange(const_iterator begin_, const_iterator end_)
- : Begin(begin_)
- , End(end_)
- {
- }
- const_iterator begin() const { return Begin; }
- const_iterator end() const { return End; }
- bool empty() const { return std::distance(Begin, End) == 0; }
- difference_type size() const { return std::distance(Begin, End); }
- cmRange& advance(KWIML_INT_intptr_t amount)
- {
- std::advance(Begin, amount);
- return *this;
- }
-
- cmRange& retreat(KWIML_INT_intptr_t amount)
- {
- std::advance(End, -amount);
- return *this;
- }
-
-private:
- const_iterator Begin;
- const_iterator End;
-};
-
typedef cmRange<std::vector<std::string>::const_iterator> cmStringRange;
class cmListFileBacktrace;
typedef cmRange<std::vector<cmListFileBacktrace>::const_iterator>
cmBacktraceRange;
-template <typename Iter1, typename Iter2>
-cmRange<Iter1> cmMakeRange(Iter1 begin, Iter2 end)
+template <typename Range>
+void cmDeleteAll(Range const& r)
{
- return cmRange<Iter1>(begin, end);
+ std::for_each(r.begin(), r.end(),
+ ContainerAlgorithms::DefaultDeleter<Range>());
}
-template <typename Range>
-cmRange<typename Range::const_iterator> cmMakeRange(Range const& range)
+template <typename T, typename Range>
+void cmAppend(std::vector<T>& v, Range const& r)
{
- return cmRange<typename Range::const_iterator>(range.begin(), range.end());
+ v.insert(v.end(), r.begin(), r.end());
}
-template <typename Range>
-void cmDeleteAll(Range const& r)
+template <typename T, typename InputIt>
+void cmAppend(std::vector<T>& v, InputIt first, InputIt last)
{
- std::for_each(r.begin(), r.end(),
- ContainerAlgorithms::DefaultDeleter<Range>());
+ v.insert(v.end(), first, last);
}
template <typename Range>
@@ -276,27 +245,45 @@ typename Range::const_iterator cmRemoveMatching(Range& r, MatchRange const& m)
ContainerAlgorithms::BinarySearcher<MatchRange>(m));
}
-template <typename Range>
-typename Range::const_iterator cmRemoveDuplicates(Range& r)
+template <typename ForwardIterator>
+ForwardIterator cmRemoveDuplicates(ForwardIterator first, ForwardIterator last)
{
- typedef typename Range::value_type T;
- std::unordered_set<T> unique;
- std::vector<size_t> indices;
- size_t count = 0;
- const typename Range::const_iterator end = r.end();
- for (typename Range::const_iterator it = r.begin(); it != end;
- ++it, ++count) {
- const typename std::unordered_set<T>::iterator occur = unique.find(*it);
- if (occur == unique.end()) {
- unique.insert(*it);
- } else {
- indices.push_back(count);
+ using Value = typename std::iterator_traits<ForwardIterator>::value_type;
+ using Hash = struct
+ {
+ std::size_t operator()(ForwardIterator it) const
+ {
+ return std::hash<Value>{}(*it);
}
+ };
+
+ using Equal = struct
+ {
+ bool operator()(ForwardIterator it1, ForwardIterator it2) const
+ {
+ return *it1 == *it2;
+ }
+ };
+ std::unordered_set<ForwardIterator, Hash, Equal> uniq;
+
+ ForwardIterator result = first;
+ while (first != last) {
+ if (uniq.find(first) == uniq.end()) {
+ if (result != first) {
+ *result = std::move(*first);
+ }
+ uniq.insert(result);
+ ++result;
+ }
+ ++first;
}
- if (indices.empty()) {
- return end;
- }
- return cmRemoveIndices(r, indices);
+ return result;
+}
+
+template <typename Range>
+typename Range::const_iterator cmRemoveDuplicates(Range& r)
+{
+ return cmRemoveDuplicates(r.begin(), r.end());
}
template <typename Range>
@@ -322,14 +309,6 @@ typename Range::const_iterator cmFindNot(Range const& r, T const& t)
return std::find_if(r.begin(), r.end(), [&t](T const& i) { return i != t; });
}
-template <typename Range>
-cmRange<typename Range::const_reverse_iterator> cmReverseRange(
- Range const& range)
-{
- return cmRange<typename Range::const_reverse_iterator>(range.rbegin(),
- range.rend());
-}
-
template <class Iter>
std::reverse_iterator<Iter> cmMakeReverseIterator(Iter it)
{
diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx
index 6e5109aa1..359d57af6 100644
--- a/Source/cmArchiveWrite.cxx
+++ b/Source/cmArchiveWrite.cxx
@@ -54,6 +54,8 @@ public:
{
}
~Entry() { archive_entry_free(this->Object); }
+ Entry(const Entry&) = delete;
+ Entry& operator=(const Entry&) = delete;
operator struct archive_entry*() { return this->Object; }
};
@@ -135,6 +137,13 @@ cmArchiveWrite::cmArchiveWrite(std::ostream& os, Compress c,
return;
}
break;
+ case CompressZstd:
+ if (archive_write_add_filter_zstd(this->Archive) != ARCHIVE_OK) {
+ this->Error = "archive_write_add_filter_zstd: ";
+ this->Error += cm_archive_error_string(this->Archive);
+ return;
+ }
+ break;
}
#if !defined(_WIN32) || defined(__CYGWIN__)
if (archive_read_disk_set_standard_lookup(this->Disk) != ARCHIVE_OK) {
@@ -177,12 +186,10 @@ cmArchiveWrite::~cmArchiveWrite()
bool cmArchiveWrite::Add(std::string path, size_t skip, const char* prefix,
bool recursive)
{
- if (this->Okay()) {
- if (!path.empty() && path.back() == '/') {
- path.erase(path.size() - 1);
- }
- this->AddPath(path.c_str(), skip, prefix, recursive);
+ if (!path.empty() && path.back() == '/') {
+ path.erase(path.size() - 1);
}
+ this->AddPath(path.c_str(), skip, prefix, recursive);
return this->Okay();
}
@@ -218,6 +225,7 @@ bool cmArchiveWrite::AddPath(const char* path, size_t skip, const char* prefix,
bool cmArchiveWrite::AddFile(const char* file, size_t skip, const char* prefix)
{
+ this->Error = "";
// Skip the file if we have no name for it. This may happen on a
// top-level directory, which does not need to be included anyway.
if (skip >= strlen(file)) {
@@ -239,7 +247,7 @@ bool cmArchiveWrite::AddFile(const char* file, size_t skip, const char* prefix)
cm_archive_entry_copy_pathname(e, dest);
if (archive_read_disk_entry_from_file(this->Disk, e, -1, nullptr) !=
ARCHIVE_OK) {
- this->Error = "archive_read_disk_entry_from_file '";
+ this->Error = "Unable to read from file '";
this->Error += file;
this->Error += "': ";
this->Error += cm_archive_error_string(this->Disk);
diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h
index 6ecdd630c..9ea88d3dc 100644
--- a/Source/cmArchiveWrite.h
+++ b/Source/cmArchiveWrite.h
@@ -49,7 +49,8 @@ public:
CompressGZip,
CompressBZip2,
CompressLZMA,
- CompressXZ
+ CompressXZ,
+ CompressZstd
};
/** Construct with output stream to which to write archive. */
@@ -58,6 +59,9 @@ public:
~cmArchiveWrite();
+ cmArchiveWrite(const cmArchiveWrite&) = delete;
+ cmArchiveWrite& operator=(const cmArchiveWrite&) = delete;
+
/**
* Add a path (file or directory) to the archive. Directories are
* added recursively. The "path" must be readable on disk, either
diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx
new file mode 100644
index 000000000..751d117f4
--- /dev/null
+++ b/Source/cmArgumentParser.cxx
@@ -0,0 +1,93 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmArgumentParser.h"
+
+#include <algorithm>
+#include <type_traits>
+
+namespace ArgumentParser {
+
+auto ActionMap::Emplace(cm::string_view name, Action action)
+ -> std::pair<iterator, bool>
+{
+ auto const it =
+ std::lower_bound(this->begin(), this->end(), name,
+ [](value_type const& elem, cm::string_view const& k) {
+ return elem.first < k;
+ });
+ return (it != this->end() && it->first == name)
+ ? std::make_pair(it, false)
+ : std::make_pair(this->emplace(it, name, std::move(action)), true);
+}
+
+auto ActionMap::Find(cm::string_view name) const -> const_iterator
+{
+ auto const it =
+ std::lower_bound(this->begin(), this->end(), name,
+ [](value_type const& elem, cm::string_view const& k) {
+ return elem.first < k;
+ });
+ return (it != this->end() && it->first == name) ? it : this->end();
+}
+
+void Instance::Bind(bool& val)
+{
+ val = true;
+ this->CurrentString = nullptr;
+ this->CurrentList = nullptr;
+ this->ExpectValue = false;
+}
+
+void Instance::Bind(std::string& val)
+{
+ this->CurrentString = &val;
+ this->CurrentList = nullptr;
+ this->ExpectValue = true;
+}
+
+void Instance::Bind(StringList& val)
+{
+ this->CurrentString = nullptr;
+ this->CurrentList = &val;
+ this->ExpectValue = true;
+}
+
+void Instance::Bind(MultiStringList& val)
+{
+ this->CurrentString = nullptr;
+ this->CurrentList = (static_cast<void>(val.emplace_back()), &val.back());
+ this->ExpectValue = false;
+}
+
+void Instance::Consume(cm::string_view arg, void* result,
+ std::vector<std::string>* unparsedArguments,
+ std::vector<std::string>* keywordsMissingValue)
+{
+ auto const it = this->Bindings.Find(arg);
+ if (it != this->Bindings.end()) {
+ it->second(*this, result);
+ if (this->ExpectValue && keywordsMissingValue != nullptr) {
+ keywordsMissingValue->emplace_back(arg);
+ }
+ 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->ExpectValue) {
+ if (keywordsMissingValue != nullptr) {
+ keywordsMissingValue->pop_back();
+ }
+ this->ExpectValue = false;
+ }
+}
+
+} // namespace ArgumentParser
diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h
new file mode 100644
index 000000000..6cfe94633
--- /dev/null
+++ b/Source/cmArgumentParser.h
@@ -0,0 +1,143 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmArgumentParser_h
+#define cmArgumentParser_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cm_static_string_view.hxx"
+#include "cm_string_view.hxx"
+
+#include <cassert>
+#include <functional>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace ArgumentParser {
+
+using StringList = std::vector<std::string>;
+using MultiStringList = std::vector<StringList>;
+
+class Instance;
+using Action = std::function<void(Instance&, void*)>;
+
+// using ActionMap = cm::flat_map<cm::string_view, Action>;
+class ActionMap : public std::vector<std::pair<cm::string_view, Action>>
+{
+public:
+ std::pair<iterator, bool> Emplace(cm::string_view name, Action action);
+ const_iterator Find(cm::string_view name) const;
+};
+
+class Instance
+{
+public:
+ Instance(ActionMap const& bindings)
+ : Bindings(bindings)
+ {
+ }
+
+ void Bind(bool& val);
+ void Bind(std::string& val);
+ void Bind(StringList& val);
+ void Bind(MultiStringList& val);
+
+ void Consume(cm::string_view arg, void* result,
+ std::vector<std::string>* unparsedArguments,
+ std::vector<std::string>* keywordsMissingValue);
+
+private:
+ ActionMap const& Bindings;
+ std::string* CurrentString = nullptr;
+ StringList* CurrentList = nullptr;
+ bool ExpectValue = false;
+};
+
+} // namespace ArgumentParser
+
+template <typename Result>
+class cmArgumentParser
+{
+public:
+ // I *think* this function could be made `constexpr` when the code is
+ // compiled as C++20. This would allow building a parser at compile time.
+ 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;
+ return *this;
+ }
+
+ template <typename Range>
+ void Parse(Result& result, Range const& args,
+ std::vector<std::string>* unparsedArguments = nullptr,
+ std::vector<std::string>* keywordsMissingValue = nullptr) const
+ {
+ ArgumentParser::Instance instance(this->Bindings);
+ for (cm::string_view arg : args) {
+ instance.Consume(arg, &result, unparsedArguments, keywordsMissingValue);
+ }
+ }
+
+ template <typename Range>
+ Result Parse(Range const& args,
+ std::vector<std::string>* unparsedArguments = nullptr,
+ std::vector<std::string>* keywordsMissingValue = nullptr) const
+ {
+ Result result;
+ this->Parse(result, args, unparsedArguments, keywordsMissingValue);
+ return result;
+ }
+
+private:
+ ArgumentParser::ActionMap Bindings;
+};
+
+template <>
+class cmArgumentParser<void>
+{
+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;
+ return *this;
+ }
+
+ template <typename Range>
+ void Parse(Range const& args,
+ std::vector<std::string>* unparsedArguments = nullptr,
+ std::vector<std::string>* keywordsMissingValue = nullptr) const
+ {
+ ArgumentParser::Instance instance(this->Bindings);
+ for (cm::string_view arg : args) {
+ instance.Consume(arg, nullptr, unparsedArguments, keywordsMissingValue);
+ }
+ }
+
+protected:
+ 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;
+ }
+
+private:
+ ArgumentParser::ActionMap Bindings;
+};
+
+#endif
diff --git a/Source/cmCMakeMinimumRequired.cxx b/Source/cmCMakeMinimumRequired.cxx
index 4218d810b..4b4bca243 100644
--- a/Source/cmCMakeMinimumRequired.cxx
+++ b/Source/cmCMakeMinimumRequired.cxx
@@ -55,7 +55,7 @@ bool cmCMakeMinimumRequired::InitialPass(std::vector<std::string> const& args,
(version_min.empty() || version_max.empty())) {
std::ostringstream e;
e << "VERSION \"" << version_string
- << "\" does not have a version on both sides of \"...\".";
+ << R"(" does not have a version on both sides of "...".)";
this->SetError(e.str());
return false;
}
diff --git a/Source/cmCMakePolicyCommand.cxx b/Source/cmCMakePolicyCommand.cxx
index ac30e1a39..8da5ef760 100644
--- a/Source/cmCMakePolicyCommand.cxx
+++ b/Source/cmCMakePolicyCommand.cxx
@@ -176,7 +176,7 @@ bool cmCMakePolicyCommand::HandleVersionMode(
(version_min.empty() || version_max.empty())) {
std::ostringstream e;
e << "VERSION \"" << version_string
- << "\" does not have a version on both sides of \"...\".";
+ << R"(" does not have a version on both sides of "...".)";
this->SetError(e.str());
return false;
}
diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx
index c0088ac5d..255a8e62a 100644
--- a/Source/cmCPluginAPI.cxx
+++ b/Source/cmCPluginAPI.cxx
@@ -167,8 +167,8 @@ void CCONV cmAddLinkDirectoryForTarget(void* arg, const char* tgt,
cmTarget* t = mf->FindLocalNonAliasTarget(tgt);
if (!t) {
cmSystemTools::Error(
- "Attempt to add link directories to non-existent target: ", tgt,
- " for directory ", d);
+ "Attempt to add link directories to non-existent target: " +
+ std::string(tgt) + " for directory " + std::string(d));
return;
}
t->InsertLinkDirectory(d, mf->GetBacktrace());
@@ -491,12 +491,16 @@ public:
typedef std::map<cmSourceFile*, cmCPluginAPISourceFile*> derived;
typedef derived::iterator iterator;
typedef derived::value_type value_type;
+ cmCPluginAPISourceFileMap() = default;
~cmCPluginAPISourceFileMap()
{
for (auto const& i : *this) {
delete i.second;
}
}
+ cmCPluginAPISourceFileMap(const cmCPluginAPISourceFileMap&) = delete;
+ cmCPluginAPISourceFileMap& operator=(const cmCPluginAPISourceFileMap&) =
+ delete;
};
cmCPluginAPISourceFileMap cmCPluginAPISourceFiles;
@@ -683,26 +687,24 @@ void CCONV cmSourceFileSetName(void* arg, const char* name, const char* dir,
}
// Next, try the various source extensions
- for (std::vector<std::string>::const_iterator ext = sourceExts.begin();
- ext != sourceExts.end(); ++ext) {
+ for (std::string const& ext : sourceExts) {
hname = pathname;
hname += ".";
- hname += *ext;
+ hname += ext;
if (cmSystemTools::FileExists(hname)) {
- sf->SourceExtension = *ext;
+ sf->SourceExtension = ext;
sf->FullPath = hname;
return;
}
}
// Finally, try the various header extensions
- for (std::vector<std::string>::const_iterator ext = headerExts.begin();
- ext != headerExts.end(); ++ext) {
+ for (std::string const& ext : headerExts) {
hname = pathname;
hname += ".";
- hname += *ext;
+ hname += ext;
if (cmSystemTools::FileExists(hname)) {
- sf->SourceExtension = *ext;
+ sf->SourceExtension = ext;
sf->FullPath = hname;
return;
}
@@ -711,13 +713,11 @@ void CCONV cmSourceFileSetName(void* arg, const char* name, const char* dir,
std::ostringstream e;
e << "Cannot find source file \"" << pathname << "\"";
e << "\n\nTried extensions";
- for (std::vector<std::string>::const_iterator ext = sourceExts.begin();
- ext != sourceExts.end(); ++ext) {
- e << " ." << *ext;
+ for (std::string const& ext : sourceExts) {
+ e << " ." << ext;
}
- for (std::vector<std::string>::const_iterator ext = headerExts.begin();
- ext != headerExts.end(); ++ext) {
- e << " ." << *ext;
+ for (std::string const& ext : headerExts) {
+ e << " ." << ext;
}
cmSystemTools::Error(e.str());
}
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 989c7ee45..d1226c3c8 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -43,7 +43,6 @@
#include "cmCTestTestHandler.h"
#include "cmCTestUpdateHandler.h"
#include "cmCTestUploadHandler.h"
-#include "cmCurl.h"
#include "cmDynamicLoader.h"
#include "cmGeneratedFileStream.h"
#include "cmGlobalGenerator.h"
@@ -62,12 +61,149 @@
# include <be/kernel/OS.h> /* disable_debugger() API. */
#endif
-#define DEBUGOUT \
- std::cout << __LINE__ << " "; \
- std::cout
-#define DEBUGERR \
- std::cerr << __LINE__ << " "; \
- std::cerr
+struct cmCTest::Private
+{
+ /** Representation of one part. */
+ struct PartInfo
+ {
+ void SetName(const std::string& name) { this->Name = name; }
+ const std::string& GetName() const { return this->Name; }
+
+ void Enable() { this->Enabled = true; }
+ explicit operator bool() const { return this->Enabled; }
+
+ std::vector<std::string> SubmitFiles;
+
+ private:
+ bool Enabled = false;
+ std::string Name;
+ };
+
+ int RepeatTests = 1; // default to run each test once
+ bool RepeatUntilFail = false;
+ std::string ConfigType;
+ std::string ScheduleType;
+ std::chrono::system_clock::time_point StopTime;
+ bool TestProgressOutput = false;
+ bool Verbose = false;
+ bool ExtraVerbose = false;
+ bool ProduceXML = false;
+ bool LabelSummary = true;
+ bool SubprojectSummary = true;
+ bool UseHTTP10 = false;
+ bool PrintLabels = false;
+ bool Failover = false;
+
+ bool FlushTestProgressLine = false;
+
+ bool ForceNewCTestProcess = false;
+
+ bool RunConfigurationScript = false;
+
+ // these are helper classes
+ cmCTestBuildHandler BuildHandler;
+ cmCTestBuildAndTestHandler BuildAndTestHandler;
+ cmCTestCoverageHandler CoverageHandler;
+ cmCTestScriptHandler ScriptHandler;
+ cmCTestTestHandler TestHandler;
+ cmCTestUpdateHandler UpdateHandler;
+ cmCTestConfigureHandler ConfigureHandler;
+ cmCTestMemCheckHandler MemCheckHandler;
+ cmCTestSubmitHandler SubmitHandler;
+ cmCTestUploadHandler UploadHandler;
+
+ std::vector<cmCTestGenericHandler*> GetTestingHandlers()
+ {
+ return { &this->BuildHandler, &this->BuildAndTestHandler,
+ &this->CoverageHandler, &this->ScriptHandler,
+ &this->TestHandler, &this->UpdateHandler,
+ &this->ConfigureHandler, &this->MemCheckHandler,
+ &this->SubmitHandler, &this->UploadHandler };
+ }
+
+ std::map<std::string, cmCTestGenericHandler*> GetNamedTestingHandlers()
+ {
+ return { { "build", &this->BuildHandler },
+ { "buildtest", &this->BuildAndTestHandler },
+ { "coverage", &this->CoverageHandler },
+ { "script", &this->ScriptHandler },
+ { "test", &this->TestHandler },
+ { "update", &this->UpdateHandler },
+ { "configure", &this->ConfigureHandler },
+ { "memcheck", &this->MemCheckHandler },
+ { "submit", &this->SubmitHandler },
+ { "upload", &this->UploadHandler } };
+ }
+
+ bool ShowOnly = false;
+ bool OutputAsJson = false;
+ int OutputAsJsonVersion = 1;
+
+ // TODO: The ctest configuration should be a hierarchy of
+ // configuration option sources: command-line, script, ini file.
+ // Then the ini file can get re-loaded whenever it changes without
+ // affecting any higher-precedence settings.
+ std::map<std::string, std::string> CTestConfiguration;
+ std::map<std::string, std::string> CTestConfigurationOverwrites;
+
+ PartInfo Parts[PartCount];
+ std::map<std::string, Part> PartMap;
+
+ std::string CurrentTag;
+ bool TomorrowTag = false;
+
+ int TestModel = cmCTest::EXPERIMENTAL;
+ std::string SpecificTrack;
+
+ cmDuration TimeOut = cmDuration::zero();
+
+ cmDuration GlobalTimeout = cmDuration::zero();
+
+ int MaxTestNameWidth = 30;
+
+ int ParallelLevel = 1;
+ bool ParallelLevelSetInCli = false;
+
+ unsigned long TestLoad = 0;
+
+ int CompatibilityMode;
+
+ // information for the --build-and-test options
+ std::string BinaryDir;
+
+ std::string NotesFiles;
+
+ bool InteractiveDebugMode = true;
+
+ bool ShortDateFormat = true;
+
+ bool CompressXMLFiles = false;
+ bool CompressTestOutput = true;
+
+ // By default we write output to the process output streams.
+ std::ostream* StreamOut = &std::cout;
+ std::ostream* StreamErr = &std::cerr;
+
+ bool SuppressUpdatingCTestConfiguration = false;
+
+ bool Debug = false;
+ bool ShowLineNumbers = false;
+ bool Quiet = false;
+
+ std::string BuildID;
+
+ std::vector<std::string> InitialCommandLineArguments;
+
+ int SubmitIndex = 0;
+
+ cmGeneratedFileStream* OutputLogFile = nullptr;
+ int OutputLogFileLastTag = -1;
+
+ bool OutputTestOutputOnTestFailure = false;
+ bool OutputColorCode = cmCTest::ColoredOutputSupportedByConsole();
+
+ std::map<std::string, std::string> Definitions;
+};
struct tm* cmCTest::GetNightlyTime(std::string const& str, bool tomorrowtag)
{
@@ -123,6 +259,11 @@ struct tm* cmCTest::GetNightlyTime(std::string const& str, bool tomorrowtag)
return lctime;
}
+bool cmCTest::GetTomorrowTag() const
+{
+ return this->Impl->TomorrowTag;
+}
+
std::string cmCTest::CleanString(const std::string& str)
{
std::string::size_type spos = str.find_first_not_of(" \n\t\r\f\v");
@@ -142,7 +283,7 @@ std::string cmCTest::CurrentTime()
struct tm* t = localtime(&currenttime);
// return ::CleanString(ctime(&currenttime));
char current_time[1024];
- if (this->ShortDateFormat) {
+ if (this->Impl->ShortDateFormat) {
strftime(current_time, 1000, "%b %d %H:%M %Z", t);
} else {
strftime(current_time, 1000, "%a %b %d %H:%M:%S %Z %Y", t);
@@ -160,88 +301,6 @@ std::string cmCTest::GetCostDataFile()
return fname;
}
-#ifdef CMAKE_BUILD_WITH_CMAKE
-static size_t HTTPResponseCallback(void* ptr, size_t size, size_t nmemb,
- void* data)
-{
- int realsize = static_cast<int>(size * nmemb);
-
- std::string* response = static_cast<std::string*>(data);
- const char* chPtr = static_cast<char*>(ptr);
- *response += chPtr;
-
- return realsize;
-}
-
-int cmCTest::HTTPRequest(std::string url, HTTPMethod method,
- std::string& response, std::string const& fields,
- std::string const& putFile, int timeout)
-{
- CURL* curl;
- FILE* file;
- ::curl_global_init(CURL_GLOBAL_ALL);
- curl = ::curl_easy_init();
- cmCurlSetCAInfo(curl);
-
- // set request options based on method
- switch (method) {
- case cmCTest::HTTP_POST:
- ::curl_easy_setopt(curl, CURLOPT_POST, 1);
- ::curl_easy_setopt(curl, CURLOPT_POSTFIELDS, fields.c_str());
- break;
- case cmCTest::HTTP_PUT:
- if (!cmSystemTools::FileExists(putFile)) {
- response = "Error: File ";
- response += putFile + " does not exist.\n";
- return -1;
- }
- ::curl_easy_setopt(curl, CURLOPT_PUT, 1);
- file = cmsys::SystemTools::Fopen(putFile, "rb");
- ::curl_easy_setopt(curl, CURLOPT_INFILE, file);
- // fall through to append GET fields
- CM_FALLTHROUGH;
- case cmCTest::HTTP_GET:
- if (!fields.empty()) {
- url += "?" + fields;
- }
- break;
- }
-
- ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
- ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
- ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
-
- // set response options
- ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HTTPResponseCallback);
- ::curl_easy_setopt(curl, CURLOPT_FILE, &response);
- ::curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
-
- CURLcode res = ::curl_easy_perform(curl);
-
- ::curl_easy_cleanup(curl);
- ::curl_global_cleanup();
-
- return static_cast<int>(res);
-}
-#endif
-
-std::string cmCTest::MakeURLSafe(const std::string& str)
-{
- std::ostringstream ost;
- char buffer[10];
- for (unsigned char ch : str) {
- if ((ch > 126 || ch < 32 || ch == '&' || ch == '%' || ch == '+' ||
- ch == '=' || ch == '@') &&
- ch != 9) {
- sprintf(buffer, "%02x;", static_cast<unsigned int>(ch));
- ost << buffer;
- } else {
- ost << ch;
- }
- }
- return ost.str();
-}
-
std::string cmCTest::DecodeURL(const std::string& in)
{
std::string out;
@@ -258,92 +317,39 @@ std::string cmCTest::DecodeURL(const std::string& in)
}
cmCTest::cmCTest()
+ : Impl(new Private)
{
- this->LabelSummary = true;
- this->SubprojectSummary = true;
- this->ParallelLevel = 1;
- this->ParallelLevelSetInCli = false;
- this->TestLoad = 0;
- this->SubmitIndex = 0;
- this->Failover = false;
- this->ForceNewCTestProcess = false;
- this->TomorrowTag = false;
- this->TestProgressOutput = false;
- this->FlushTestProgressLine = false;
- this->Verbose = false;
-
- this->Debug = false;
- this->ShowLineNumbers = false;
- this->Quiet = false;
- this->ExtraVerbose = false;
- this->ProduceXML = false;
- this->ShowOnly = false;
- this->OutputAsJson = false;
- this->OutputAsJsonVersion = 1;
- this->RunConfigurationScript = false;
- this->UseHTTP10 = false;
- this->PrintLabels = false;
- this->CompressTestOutput = true;
- this->TestModel = cmCTest::EXPERIMENTAL;
- this->MaxTestNameWidth = 30;
- this->InteractiveDebugMode = true;
- this->TimeOut = cmDuration::zero();
- this->GlobalTimeout = cmDuration::zero();
- this->CompressXMLFiles = false;
- this->ScheduleType.clear();
- this->OutputLogFile = nullptr;
- this->OutputLogFileLastTag = -1;
- this->SuppressUpdatingCTestConfiguration = false;
- this->BuildID = "";
- this->OutputTestOutputOnTestFailure = false;
- this->OutputColorCode = cmCTest::ColoredOutputSupportedByConsole();
- this->RepeatTests = 1; // default to run each test once
- this->RepeatUntilFail = false;
-
std::string envValue;
if (cmSystemTools::GetEnv("CTEST_OUTPUT_ON_FAILURE", envValue)) {
- this->OutputTestOutputOnTestFailure = !cmSystemTools::IsOff(envValue);
+ this->Impl->OutputTestOutputOnTestFailure =
+ !cmSystemTools::IsOff(envValue);
}
envValue.clear();
if (cmSystemTools::GetEnv("CTEST_PROGRESS_OUTPUT", envValue)) {
- this->TestProgressOutput = !cmSystemTools::IsOff(envValue);
- }
-
- this->InitStreams();
-
- this->Parts[PartStart].SetName("Start");
- this->Parts[PartUpdate].SetName("Update");
- this->Parts[PartConfigure].SetName("Configure");
- this->Parts[PartBuild].SetName("Build");
- this->Parts[PartTest].SetName("Test");
- this->Parts[PartCoverage].SetName("Coverage");
- this->Parts[PartMemCheck].SetName("MemCheck");
- this->Parts[PartSubmit].SetName("Submit");
- this->Parts[PartNotes].SetName("Notes");
- this->Parts[PartExtraFiles].SetName("ExtraFiles");
- this->Parts[PartUpload].SetName("Upload");
- this->Parts[PartDone].SetName("Done");
+ this->Impl->TestProgressOutput = !cmSystemTools::IsOff(envValue);
+ }
+
+ this->Impl->Parts[PartStart].SetName("Start");
+ this->Impl->Parts[PartUpdate].SetName("Update");
+ this->Impl->Parts[PartConfigure].SetName("Configure");
+ this->Impl->Parts[PartBuild].SetName("Build");
+ this->Impl->Parts[PartTest].SetName("Test");
+ this->Impl->Parts[PartCoverage].SetName("Coverage");
+ this->Impl->Parts[PartMemCheck].SetName("MemCheck");
+ this->Impl->Parts[PartSubmit].SetName("Submit");
+ this->Impl->Parts[PartNotes].SetName("Notes");
+ this->Impl->Parts[PartExtraFiles].SetName("ExtraFiles");
+ this->Impl->Parts[PartUpload].SetName("Upload");
+ this->Impl->Parts[PartDone].SetName("Done");
// Fill the part name-to-id map.
for (Part p = PartStart; p != PartCount; p = Part(p + 1)) {
- this->PartMap[cmSystemTools::LowerCase(this->Parts[p].GetName())] = p;
+ this->Impl
+ ->PartMap[cmSystemTools::LowerCase(this->Impl->Parts[p].GetName())] = p;
}
- this->ShortDateFormat = true;
-
- this->TestingHandlers["build"] = new cmCTestBuildHandler;
- this->TestingHandlers["buildtest"] = new cmCTestBuildAndTestHandler;
- this->TestingHandlers["coverage"] = new cmCTestCoverageHandler;
- this->TestingHandlers["script"] = new cmCTestScriptHandler;
- this->TestingHandlers["test"] = new cmCTestTestHandler;
- this->TestingHandlers["update"] = new cmCTestUpdateHandler;
- this->TestingHandlers["configure"] = new cmCTestConfigureHandler;
- this->TestingHandlers["memcheck"] = new cmCTestMemCheckHandler;
- this->TestingHandlers["submit"] = new cmCTestSubmitHandler;
- this->TestingHandlers["upload"] = new cmCTestUploadHandler;
-
- for (auto& handler : this->TestingHandlers) {
- handler.second->SetCTestInstance(this);
+ for (auto& handler : this->Impl->GetTestingHandlers()) {
+ handler->SetCTestInstance(this);
}
// Make sure we can capture the build tool output.
@@ -352,31 +358,40 @@ cmCTest::cmCTest()
cmCTest::~cmCTest()
{
- cmDeleteAll(this->TestingHandlers);
- this->SetOutputLogFileName(nullptr);
+ delete this->Impl->OutputLogFile;
+}
+
+int cmCTest::GetParallelLevel() const
+{
+ return this->Impl->ParallelLevel;
}
void cmCTest::SetParallelLevel(int level)
{
- this->ParallelLevel = level < 1 ? 1 : level;
+ this->Impl->ParallelLevel = level < 1 ? 1 : level;
+}
+
+unsigned long cmCTest::GetTestLoad() const
+{
+ return this->Impl->TestLoad;
}
void cmCTest::SetTestLoad(unsigned long load)
{
- this->TestLoad = load;
+ this->Impl->TestLoad = load;
}
bool cmCTest::ShouldCompressTestOutput()
{
- return this->CompressTestOutput;
+ return this->Impl->CompressTestOutput;
}
cmCTest::Part cmCTest::GetPartFromName(const char* name)
{
// Look up by lower-case to make names case-insensitive.
std::string lower_name = cmSystemTools::LowerCase(name);
- PartMapType::const_iterator i = this->PartMap.find(lower_name);
- if (i != this->PartMap.end()) {
+ auto const i = this->Impl->PartMap.find(lower_name);
+ if (i != this->Impl->PartMap.end()) {
return i->second;
}
@@ -392,19 +407,19 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
}
cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
- if (!this->InteractiveDebugMode) {
+ if (!this->Impl->InteractiveDebugMode) {
this->BlockTestErrorDiagnostics();
} else {
cmSystemTools::PutEnv("CTEST_INTERACTIVE_DEBUG_MODE=1");
}
- this->BinaryDir = binary_dir;
- cmSystemTools::ConvertToUnixSlashes(this->BinaryDir);
+ this->Impl->BinaryDir = binary_dir;
+ cmSystemTools::ConvertToUnixSlashes(this->Impl->BinaryDir);
this->UpdateCTestConfiguration();
cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
- if (this->ProduceXML) {
+ if (this->Impl->ProduceXML) {
cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
cmCTestOptionalLog(this, OUTPUT,
" Site: "
@@ -415,7 +430,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
<< std::endl,
quiet);
cmCTestOptionalLog(this, DEBUG, "Produce XML is on" << std::endl, quiet);
- if (this->TestModel == cmCTest::NIGHTLY &&
+ if (this->Impl->TestModel == cmCTest::NIGHTLY &&
this->GetCTestConfiguration("NightlyStartTime").empty()) {
cmCTestOptionalLog(
this, WARNING,
@@ -435,17 +450,18 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
cm.GetCurrentSnapshot().SetDefaultDefinitions();
cmGlobalGenerator gg(&cm);
cmMakefile mf(&gg, cm.GetCurrentSnapshot());
- if (!this->ReadCustomConfigurationFileTree(this->BinaryDir.c_str(), &mf)) {
+ if (!this->ReadCustomConfigurationFileTree(this->Impl->BinaryDir.c_str(),
+ &mf)) {
cmCTestOptionalLog(
this, DEBUG, "Cannot find custom configuration file tree" << std::endl,
quiet);
return 0;
}
- if (this->ProduceXML) {
+ if (this->Impl->ProduceXML) {
// Verify "Testing" directory exists:
//
- std::string testingDir = this->BinaryDir + "/Testing";
+ std::string testingDir = this->Impl->BinaryDir + "/Testing";
if (cmSystemTools::FileExists(testingDir)) {
if (!cmSystemTools::FileIsDirectory(testingDir)) {
cmCTestLog(this, ERROR_MESSAGE,
@@ -475,7 +491,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
if (createNewTag) {
time_t tctime = time(nullptr);
- if (this->TomorrowTag) {
+ if (this->Impl->TomorrowTag) {
tctime += (24 * 60 * 60);
}
struct tm* lctime = gmtime(&tctime);
@@ -493,26 +509,28 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
}
std::string track;
if (cmSystemTools::GetLineFromStream(tfin, track) &&
- !this->Parts[PartStart] && !command) {
- this->SpecificTrack = track;
+ !this->Impl->Parts[PartStart] && !command) {
+ this->Impl->SpecificTrack = track;
}
std::string model;
if (cmSystemTools::GetLineFromStream(tfin, model) &&
- !this->Parts[PartStart] && !command) {
- this->TestModel = GetTestModelFromString(model.c_str());
+ !this->Impl->Parts[PartStart] && !command) {
+ this->Impl->TestModel = GetTestModelFromString(model.c_str());
}
tfin.close();
}
- if (tag.empty() || (nullptr != command) || this->Parts[PartStart]) {
+ if (tag.empty() || (nullptr != command) ||
+ this->Impl->Parts[PartStart]) {
cmCTestOptionalLog(
this, DEBUG,
"TestModel: " << this->GetTestModelString() << std::endl, quiet);
- cmCTestOptionalLog(
- this, DEBUG, "TestModel: " << this->TestModel << std::endl, quiet);
- if (this->TestModel == cmCTest::NIGHTLY) {
+ cmCTestOptionalLog(this, DEBUG,
+ "TestModel: " << this->Impl->TestModel << std::endl,
+ quiet);
+ if (this->Impl->TestModel == cmCTest::NIGHTLY) {
lctime = this->GetNightlyTime(
this->GetCTestConfiguration("NightlyStartTime"),
- this->TomorrowTag);
+ this->Impl->TomorrowTag);
}
char datestring[100];
sprintf(datestring, "%04d%02d%02d-%02d%02d", lctime->tm_year + 1900,
@@ -523,7 +541,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
if (ofs) {
ofs << tag << std::endl;
ofs << this->GetTestModelString() << std::endl;
- switch (this->TestModel) {
+ switch (this->Impl->TestModel) {
case cmCTest::EXPERIMENTAL:
ofs << "Experimental" << std::endl;
break;
@@ -565,7 +583,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
return 0;
}
- if (this->TestModel == cmCTest::UNKNOWN) {
+ if (this->Impl->TestModel == cmCTest::UNKNOWN) {
if (model == cmCTest::UNKNOWN) {
cmCTestLog(this, ERROR_MESSAGE,
"TAG file does not contain model and "
@@ -577,8 +595,8 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
this->SetTestModel(model);
}
- if (model != this->TestModel && model != cmCTest::UNKNOWN &&
- this->TestModel != cmCTest::UNKNOWN) {
+ if (model != this->Impl->TestModel && model != cmCTest::UNKNOWN &&
+ this->Impl->TestModel != cmCTest::UNKNOWN) {
cmCTestOptionalLog(this, WARNING,
"Model given in TAG does not match "
"model given in ctest_start()"
@@ -586,14 +604,15 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
quiet);
}
- if (!this->SpecificTrack.empty() && track != this->SpecificTrack) {
+ if (!this->Impl->SpecificTrack.empty() &&
+ track != this->Impl->SpecificTrack) {
cmCTestOptionalLog(this, WARNING,
"Track given in TAG does not match "
"track given in ctest_start()"
<< std::endl,
quiet);
} else {
- this->SpecificTrack = track;
+ this->Impl->SpecificTrack = track;
}
cmCTestOptionalLog(this, OUTPUT,
@@ -603,7 +622,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
quiet);
}
- this->CurrentTag = tag;
+ this->Impl->CurrentTag = tag;
}
return 1;
@@ -613,9 +632,9 @@ bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command)
{
std::string src_dir = this->GetCTestConfiguration("SourceDirectory");
std::string bld_dir = this->GetCTestConfiguration("BuildDirectory");
- this->BuildID = "";
+ this->Impl->BuildID = "";
for (Part p = PartStart; p != PartCount; p = Part(p + 1)) {
- this->Parts[p].SubmitFiles.clear();
+ this->Impl->Parts[p].SubmitFiles.clear();
}
cmMakefile* mf = command->GetMakefile();
@@ -669,18 +688,18 @@ bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command)
bool cmCTest::UpdateCTestConfiguration()
{
- if (this->SuppressUpdatingCTestConfiguration) {
+ if (this->Impl->SuppressUpdatingCTestConfiguration) {
return true;
}
- std::string fileName = this->BinaryDir + "/CTestConfiguration.ini";
+ std::string fileName = this->Impl->BinaryDir + "/CTestConfiguration.ini";
if (!cmSystemTools::FileExists(fileName)) {
- fileName = this->BinaryDir + "/DartConfiguration.tcl";
+ fileName = this->Impl->BinaryDir + "/DartConfiguration.tcl";
}
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
"UpdateCTestConfiguration from :" << fileName << "\n");
if (!cmSystemTools::FileExists(fileName)) {
// No need to exit if we are not producing XML
- if (this->ProduceXML) {
+ if (this->Impl->ProduceXML) {
cmCTestLog(this, ERROR_MESSAGE,
"Cannot find file: " << fileName << std::endl);
return false;
@@ -720,15 +739,15 @@ bool cmCTest::UpdateCTestConfiguration()
}
std::string key = line.substr(0, cpos);
std::string value = cmCTest::CleanString(line.substr(cpos + 1));
- this->CTestConfiguration[key] = value;
+ this->Impl->CTestConfiguration[key] = value;
}
fin.close();
}
if (!this->GetCTestConfiguration("BuildDirectory").empty()) {
- this->BinaryDir = this->GetCTestConfiguration("BuildDirectory");
- cmSystemTools::ChangeDirectory(this->BinaryDir);
+ this->Impl->BinaryDir = this->GetCTestConfiguration("BuildDirectory");
+ cmSystemTools::ChangeDirectory(this->Impl->BinaryDir);
}
- this->TimeOut =
+ this->Impl->TimeOut =
std::chrono::seconds(atoi(this->GetCTestConfiguration("TimeOut").c_str()));
std::string const& testLoad = this->GetCTestConfiguration("TestLoad");
if (!testLoad.empty()) {
@@ -740,8 +759,8 @@ bool cmCTest::UpdateCTestConfiguration()
"Invalid value for 'Test Load' : " << testLoad << std::endl);
}
}
- if (this->ProduceXML) {
- this->CompressXMLFiles =
+ if (this->Impl->ProduceXML) {
+ this->Impl->CompressXMLFiles =
cmSystemTools::IsOn(this->GetCTestConfiguration("CompressSubmission"));
}
return true;
@@ -760,21 +779,26 @@ void cmCTest::BlockTestErrorDiagnostics()
void cmCTest::SetTestModel(int mode)
{
- this->InteractiveDebugMode = false;
- this->TestModel = mode;
+ this->Impl->InteractiveDebugMode = false;
+ this->Impl->TestModel = mode;
+}
+
+int cmCTest::GetTestModel() const
+{
+ return this->Impl->TestModel;
}
bool cmCTest::SetTest(const char* ttype, bool report)
{
if (cmSystemTools::LowerCase(ttype) == "all") {
for (Part p = PartStart; p != PartCount; p = Part(p + 1)) {
- this->Parts[p].Enable();
+ this->Impl->Parts[p].Enable();
}
return true;
}
Part p = this->GetPartFromName(ttype);
if (p != PartCount) {
- this->Parts[p].Enable();
+ this->Impl->Parts[p].Enable();
return true;
}
if (report) {
@@ -792,7 +816,7 @@ void cmCTest::Finalize()
bool cmCTest::OpenOutputFile(const std::string& path, const std::string& name,
cmGeneratedFileStream& stream, bool compress)
{
- std::string testingDir = this->BinaryDir + "/Testing";
+ std::string testingDir = this->Impl->BinaryDir + "/Testing";
if (!path.empty()) {
testingDir += "/" + path;
}
@@ -819,7 +843,7 @@ bool cmCTest::OpenOutputFile(const std::string& path, const std::string& name,
return false;
}
if (compress) {
- if (this->CompressXMLFiles) {
+ if (this->Impl->CompressXMLFiles) {
stream.SetCompression(true);
}
}
@@ -844,40 +868,59 @@ bool cmCTest::AddIfExists(Part part, const char* file)
bool cmCTest::CTestFileExists(const std::string& filename)
{
- std::string testingDir =
- this->BinaryDir + "/Testing/" + this->CurrentTag + "/" + filename;
+ std::string testingDir = this->Impl->BinaryDir + "/Testing/" +
+ this->Impl->CurrentTag + "/" + filename;
return cmSystemTools::FileExists(testingDir);
}
-cmCTestGenericHandler* cmCTest::GetInitializedHandler(const char* handler)
+cmCTestBuildHandler* cmCTest::GetBuildHandler()
{
- cmCTest::t_TestingHandlers::iterator it =
- this->TestingHandlers.find(handler);
- if (it == this->TestingHandlers.end()) {
- return nullptr;
- }
- it->second->Initialize();
- return it->second;
+ return &this->Impl->BuildHandler;
}
-cmCTestGenericHandler* cmCTest::GetHandler(const char* handler)
+cmCTestBuildAndTestHandler* cmCTest::GetBuildAndTestHandler()
{
- cmCTest::t_TestingHandlers::iterator it =
- this->TestingHandlers.find(handler);
- if (it == this->TestingHandlers.end()) {
- return nullptr;
- }
- return it->second;
+ return &this->Impl->BuildAndTestHandler;
}
-int cmCTest::ExecuteHandler(const char* shandler)
+cmCTestCoverageHandler* cmCTest::GetCoverageHandler()
{
- cmCTestGenericHandler* handler = this->GetHandler(shandler);
- if (!handler) {
- return -1;
- }
- handler->Initialize();
- return handler->ProcessHandler();
+ return &this->Impl->CoverageHandler;
+}
+
+cmCTestScriptHandler* cmCTest::GetScriptHandler()
+{
+ return &this->Impl->ScriptHandler;
+}
+
+cmCTestTestHandler* cmCTest::GetTestHandler()
+{
+ return &this->Impl->TestHandler;
+}
+
+cmCTestUpdateHandler* cmCTest::GetUpdateHandler()
+{
+ return &this->Impl->UpdateHandler;
+}
+
+cmCTestConfigureHandler* cmCTest::GetConfigureHandler()
+{
+ return &this->Impl->ConfigureHandler;
+}
+
+cmCTestMemCheckHandler* cmCTest::GetMemCheckHandler()
+{
+ return &this->Impl->MemCheckHandler;
+}
+
+cmCTestSubmitHandler* cmCTest::GetSubmitHandler()
+{
+ return &this->Impl->SubmitHandler;
+}
+
+cmCTestUploadHandler* cmCTest::GetUploadHandler()
+{
+ return &this->Impl->UploadHandler;
}
int cmCTest::ProcessSteps()
@@ -887,11 +930,11 @@ int cmCTest::ProcessSteps()
int update_count = 0;
for (Part p = PartStart; notest && p != PartCount; p = Part(p + 1)) {
- notest = !this->Parts[p];
+ notest = !this->Impl->Parts[p];
}
- if (this->Parts[PartUpdate] &&
+ if (this->Impl->Parts[PartUpdate] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
- cmCTestGenericHandler* uphandler = this->GetHandler("update");
+ cmCTestUpdateHandler* uphandler = this->GetUpdateHandler();
uphandler->SetPersistentOption(
"SourceDirectory",
this->GetCTestConfiguration("SourceDirectory").c_str());
@@ -900,45 +943,45 @@ int cmCTest::ProcessSteps()
res |= cmCTest::UPDATE_ERRORS;
}
}
- if (this->TestModel == cmCTest::CONTINUOUS && !update_count) {
+ if (this->Impl->TestModel == cmCTest::CONTINUOUS && !update_count) {
return 0;
}
- if (this->Parts[PartConfigure] &&
+ if (this->Impl->Parts[PartConfigure] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
- if (this->GetHandler("configure")->ProcessHandler() < 0) {
+ if (this->GetConfigureHandler()->ProcessHandler() < 0) {
res |= cmCTest::CONFIGURE_ERRORS;
}
}
- if (this->Parts[PartBuild] &&
+ if (this->Impl->Parts[PartBuild] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
this->UpdateCTestConfiguration();
- if (this->GetHandler("build")->ProcessHandler() < 0) {
+ if (this->GetBuildHandler()->ProcessHandler() < 0) {
res |= cmCTest::BUILD_ERRORS;
}
}
- if ((this->Parts[PartTest] || notest) &&
+ if ((this->Impl->Parts[PartTest] || notest) &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
this->UpdateCTestConfiguration();
- if (this->GetHandler("test")->ProcessHandler() < 0) {
+ if (this->GetTestHandler()->ProcessHandler() < 0) {
res |= cmCTest::TEST_ERRORS;
}
}
- if (this->Parts[PartCoverage] &&
+ if (this->Impl->Parts[PartCoverage] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
this->UpdateCTestConfiguration();
- if (this->GetHandler("coverage")->ProcessHandler() < 0) {
+ if (this->GetCoverageHandler()->ProcessHandler() < 0) {
res |= cmCTest::COVERAGE_ERRORS;
}
}
- if (this->Parts[PartMemCheck] &&
+ if (this->Impl->Parts[PartMemCheck] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
this->UpdateCTestConfiguration();
- if (this->GetHandler("memcheck")->ProcessHandler() < 0) {
+ if (this->GetMemCheckHandler()->ProcessHandler() < 0) {
res |= cmCTest::MEMORY_ERRORS;
}
}
if (!notest) {
- std::string notes_dir = this->BinaryDir + "/Testing/Notes";
+ std::string notes_dir = this->Impl->BinaryDir + "/Testing/Notes";
if (cmSystemTools::FileIsDirectory(notes_dir)) {
cmsys::Directory d;
d.Load(notes_dir);
@@ -948,24 +991,24 @@ int cmCTest::ProcessSteps()
std::string fullname = notes_dir + "/" + file;
if (cmSystemTools::FileExists(fullname) &&
!cmSystemTools::FileIsDirectory(fullname)) {
- if (!this->NotesFiles.empty()) {
- this->NotesFiles += ";";
+ if (!this->Impl->NotesFiles.empty()) {
+ this->Impl->NotesFiles += ";";
}
- this->NotesFiles += fullname;
- this->Parts[PartNotes].Enable();
+ this->Impl->NotesFiles += fullname;
+ this->Impl->Parts[PartNotes].Enable();
}
}
}
}
- if (this->Parts[PartNotes]) {
+ if (this->Impl->Parts[PartNotes]) {
this->UpdateCTestConfiguration();
- if (!this->NotesFiles.empty()) {
- this->GenerateNotesFile(this->NotesFiles.c_str());
+ if (!this->Impl->NotesFiles.empty()) {
+ this->GenerateNotesFile(this->Impl->NotesFiles.c_str());
}
}
- if (this->Parts[PartSubmit]) {
+ if (this->Impl->Parts[PartSubmit]) {
this->UpdateCTestConfiguration();
- if (this->GetHandler("submit")->ProcessHandler() < 0) {
+ if (this->GetSubmitHandler()->ProcessHandler() < 0) {
res |= cmCTest::SUBMIT_ERRORS;
}
}
@@ -977,10 +1020,10 @@ int cmCTest::ProcessSteps()
std::string cmCTest::GetTestModelString()
{
- if (!this->SpecificTrack.empty()) {
- return this->SpecificTrack;
+ if (!this->Impl->SpecificTrack.empty()) {
+ return this->Impl->SpecificTrack;
}
- switch (this->TestModel) {
+ switch (this->Impl->TestModel) {
case cmCTest::NIGHTLY:
return "Nightly";
case cmCTest::CONTINUOUS:
@@ -1009,7 +1052,7 @@ int cmCTest::GetTestModelFromString(const char* str)
//######################################################################
//######################################################################
-int cmCTest::RunMakeCommand(const char* command, std::string& output,
+int cmCTest::RunMakeCommand(const std::string& command, std::string& output,
int* retVal, const char* dir, cmDuration timeout,
std::ostream& ofs, Encoding encoding)
{
@@ -1039,7 +1082,7 @@ int cmCTest::RunMakeCommand(const char* command, std::string& output,
// Now create process object
cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetCommand(cp, argv.data());
cmsysProcess_SetWorkingDirectory(cp, dir);
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
cmsysProcess_SetTimeout(cp, timeout.count());
@@ -1139,8 +1182,9 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
if (timeout != cmCTest::MaxDuration()) {
timeout -= std::chrono::minutes(2);
}
- if (this->TimeOut > cmDuration::zero() && this->TimeOut < timeout) {
- timeout = this->TimeOut;
+ if (this->Impl->TimeOut > cmDuration::zero() &&
+ this->Impl->TimeOut < timeout) {
+ timeout = this->Impl->TimeOut;
}
if (testTimeOut > cmDuration::zero() &&
testTimeOut < this->GetRemainingTimeAllowed()) {
@@ -1158,10 +1202,10 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
: std::to_string(cmDurationTo<unsigned int>(timeout)))
<< "\n");
if (cmSystemTools::SameFile(argv[0], cmSystemTools::GetCTestCommand()) &&
- !this->ForceNewCTestProcess) {
+ !this->Impl->ForceNewCTestProcess) {
cmCTest inst;
- inst.ConfigType = this->ConfigType;
- inst.TimeOut = timeout;
+ inst.Impl->ConfigType = this->Impl->ConfigType;
+ inst.Impl->TimeOut = timeout;
// Capture output of the child ctest.
std::ostringstream oss;
@@ -1222,7 +1266,7 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
}
cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetCommand(cp, argv.data());
cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
if (cmSystemTools::GetRunCommandHideConsole()) {
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
@@ -1238,7 +1282,7 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
processOutput.DecodeText(data, length, strdata);
if (output) {
- tempOutput.insert(tempOutput.end(), data, data + length);
+ cmAppend(tempOutput, data, data + length);
}
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
cmCTestLogWrite(strdata.c_str(), strdata.size()));
@@ -1258,7 +1302,7 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
cmsysProcess_WaitForExit(cp, nullptr);
processOutput.DecodeText(tempOutput, tempOutput);
if (output && tempOutput.begin() != tempOutput.end()) {
- output->append(&*tempOutput.begin(), tempOutput.size());
+ output->append(tempOutput.data(), tempOutput.size());
}
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
"-- Process completed" << std::endl);
@@ -1267,11 +1311,11 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
if (result == cmsysProcess_State_Exited) {
*retVal = cmsysProcess_GetExitValue(cp);
- if (*retVal != 0 && this->OutputTestOutputOnTestFailure) {
+ if (*retVal != 0 && this->Impl->OutputTestOutputOnTestFailure) {
OutputTestErrors(tempOutput);
}
} else if (result == cmsysProcess_State_Exception) {
- if (this->OutputTestOutputOnTestFailure) {
+ if (this->Impl->OutputTestOutputOnTestFailure) {
OutputTestErrors(tempOutput);
}
*retVal = cmsysProcess_GetExitException(cp);
@@ -1330,7 +1374,7 @@ std::string cmCTest::SafeBuildIdField(const std::string& value)
void cmCTest::StartXML(cmXMLWriter& xml, bool append)
{
- if (this->CurrentTag.empty()) {
+ if (this->Impl->CurrentTag.empty()) {
cmCTestLog(this, ERROR_MESSAGE,
"Current Tag empty, this may mean"
" NightlStartTime was not set correctly."
@@ -1346,7 +1390,7 @@ void cmCTest::StartXML(cmXMLWriter& xml, bool append)
std::string buildname =
cmCTest::SafeBuildIdField(this->GetCTestConfiguration("BuildName"));
- std::string stamp = cmCTest::SafeBuildIdField(this->CurrentTag + "-" +
+ std::string stamp = cmCTest::SafeBuildIdField(this->Impl->CurrentTag + "-" +
this->GetTestModelString());
std::string site =
cmCTest::SafeBuildIdField(this->GetCTestConfiguration("Site"));
@@ -1394,8 +1438,7 @@ void cmCTest::StartXML(cmXMLWriter& xml, bool append)
void cmCTest::AddSiteProperties(cmXMLWriter& xml)
{
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+ cmCTestScriptHandler* ch = this->GetScriptHandler();
cmake* cm = ch->GetCMake();
// if no CMake then this is the old style script and props like
// this will not work anyway.
@@ -1465,7 +1508,7 @@ void cmCTest::EndXML(cmXMLWriter& xml)
}
int cmCTest::GenerateCTestNotesOutput(cmXMLWriter& xml,
- const cmCTest::VectorOfStrings& files)
+ std::vector<std::string> const& files)
{
std::string buildname =
cmCTest::SafeBuildIdField(this->GetCTestConfiguration("BuildName"));
@@ -1477,10 +1520,10 @@ int cmCTest::GenerateCTestNotesOutput(cmXMLWriter& xml,
xml.StartElement("Site");
xml.Attribute("BuildName", buildname);
xml.Attribute("BuildStamp",
- this->CurrentTag + "-" + this->GetTestModelString());
+ this->Impl->CurrentTag + "-" + this->GetTestModelString());
xml.Attribute("Name", this->GetCTestConfiguration("Site"));
xml.Attribute("Generator",
- std::string("ctest") + cmVersion::GetCMakeVersion());
+ std::string("ctest-") + cmVersion::GetCMakeVersion());
this->AddSiteProperties(xml);
xml.StartElement("Notes");
@@ -1515,10 +1558,10 @@ int cmCTest::GenerateCTestNotesOutput(cmXMLWriter& xml,
return 1;
}
-int cmCTest::GenerateNotesFile(const VectorOfStrings& files)
+int cmCTest::GenerateNotesFile(std::vector<std::string> const& files)
{
cmGeneratedFileStream ofs;
- if (!this->OpenOutputFile(this->CurrentTag, "Notes.xml", ofs)) {
+ if (!this->OpenOutputFile(this->Impl->CurrentTag, "Notes.xml", ofs)) {
cmCTestLog(this, ERROR_MESSAGE, "Cannot open notes file" << std::endl);
return 1;
}
@@ -1533,11 +1576,10 @@ int cmCTest::GenerateNotesFile(const char* cfiles)
return 1;
}
- VectorOfStrings files;
-
cmCTestLog(this, OUTPUT, "Create notes file" << std::endl);
- files = cmSystemTools::SplitString(cfiles, ';');
+ std::vector<std::string> const files =
+ cmSystemTools::SplitString(cfiles, ';');
if (files.empty()) {
return 1;
}
@@ -1548,14 +1590,14 @@ int cmCTest::GenerateNotesFile(const char* cfiles)
int cmCTest::GenerateDoneFile()
{
cmGeneratedFileStream ofs;
- if (!this->OpenOutputFile(this->CurrentTag, "Done.xml", ofs)) {
+ if (!this->OpenOutputFile(this->Impl->CurrentTag, "Done.xml", ofs)) {
cmCTestLog(this, ERROR_MESSAGE, "Cannot open done file" << std::endl);
return 1;
}
cmXMLWriter xml(ofs);
xml.StartDocument();
xml.StartElement("Done");
- xml.Element("buildId", this->BuildID);
+ xml.Element("buildId", this->Impl->BuildID);
xml.Element("time", std::chrono::system_clock::now());
xml.EndElement(); // Done
xml.EndDocument();
@@ -1569,8 +1611,8 @@ std::string cmCTest::Base64GzipEncodeFile(std::string const& file)
std::vector<std::string> files;
files.push_back(file);
- if (!cmSystemTools::CreateTar(tarFile.c_str(), files,
- cmSystemTools::TarCompressGZip, false)) {
+ if (!cmSystemTools::CreateTar(tarFile, files, cmSystemTools::TarCompressGZip,
+ false)) {
cmCTestLog(this, ERROR_MESSAGE,
"Error creating tar while "
"encoding file: "
@@ -1604,7 +1646,7 @@ std::string cmCTest::Base64EncodeFile(std::string const& file)
return std::string(&encoded_buffer[0], rlen);
}
-bool cmCTest::SubmitExtraFiles(const VectorOfStrings& files)
+bool cmCTest::SubmitExtraFiles(std::vector<std::string> const& files)
{
for (std::string const& file : files) {
if (!cmSystemTools::FileExists(file)) {
@@ -1624,11 +1666,10 @@ bool cmCTest::SubmitExtraFiles(const char* cfiles)
return true;
}
- VectorOfStrings files;
-
cmCTestLog(this, OUTPUT, "Submit extra files" << std::endl);
- files = cmSystemTools::SplitString(cfiles, ';');
+ std::vector<std::string> const files =
+ cmSystemTools::SplitString(cfiles, ';');
if (files.empty()) {
return true;
}
@@ -1796,17 +1837,17 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
{
std::string arg = args[i];
if (this->CheckArgument(arg, "-F")) {
- this->Failover = true;
+ this->Impl->Failover = true;
}
if (this->CheckArgument(arg, "-j", "--parallel") && i < args.size() - 1) {
i++;
int plevel = atoi(args[i].c_str());
this->SetParallelLevel(plevel);
- this->ParallelLevelSetInCli = true;
+ this->Impl->ParallelLevelSetInCli = true;
} else if (arg.find("-j") == 0) {
int plevel = atoi(arg.substr(2).c_str());
this->SetParallelLevel(plevel);
- this->ParallelLevelSetInCli = true;
+ this->Impl->ParallelLevelSetInCli = true;
}
if (this->CheckArgument(arg, "--repeat-until-fail")) {
if (i >= args.size() - 1) {
@@ -1820,9 +1861,9 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
"'--repeat-until-fail' given non-integer value '" + args[i] + "'";
return false;
}
- this->RepeatTests = static_cast<int>(repeat);
+ this->Impl->RepeatTests = static_cast<int>(repeat);
if (repeat > 1) {
- this->RepeatUntilFail = true;
+ this->Impl->RepeatUntilFail = true;
}
}
@@ -1838,21 +1879,21 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
}
if (this->CheckArgument(arg, "--no-compress-output")) {
- this->CompressTestOutput = false;
+ this->Impl->CompressTestOutput = false;
}
if (this->CheckArgument(arg, "--print-labels")) {
- this->PrintLabels = true;
+ this->Impl->PrintLabels = true;
}
if (this->CheckArgument(arg, "--http1.0")) {
- this->UseHTTP10 = true;
+ this->Impl->UseHTTP10 = true;
}
if (this->CheckArgument(arg, "--timeout") && i < args.size() - 1) {
i++;
auto timeout = cmDuration(atof(args[i].c_str()));
- this->GlobalTimeout = timeout;
+ this->Impl->GlobalTimeout = timeout;
}
if (this->CheckArgument(arg, "--stop-time") && i < args.size() - 1) {
@@ -1867,47 +1908,44 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
}
if (this->CheckArgument(arg, "--debug")) {
- this->Debug = true;
- this->ShowLineNumbers = true;
+ this->Impl->Debug = true;
+ this->Impl->ShowLineNumbers = true;
}
if (this->CheckArgument(arg, "--track") && i < args.size() - 1) {
i++;
- this->SpecificTrack = args[i];
+ this->Impl->SpecificTrack = args[i];
}
if (this->CheckArgument(arg, "--show-line-numbers")) {
- this->ShowLineNumbers = true;
+ this->Impl->ShowLineNumbers = true;
}
if (this->CheckArgument(arg, "--no-label-summary")) {
- this->LabelSummary = false;
+ this->Impl->LabelSummary = false;
}
if (this->CheckArgument(arg, "--no-subproject-summary")) {
- this->SubprojectSummary = false;
+ this->Impl->SubprojectSummary = false;
}
if (this->CheckArgument(arg, "-Q", "--quiet")) {
- this->Quiet = true;
+ this->Impl->Quiet = true;
}
if (this->CheckArgument(arg, "--progress")) {
- this->TestProgressOutput = true;
+ this->Impl->TestProgressOutput = true;
}
if (this->CheckArgument(arg, "-V", "--verbose")) {
- this->Verbose = true;
+ this->Impl->Verbose = true;
}
if (this->CheckArgument(arg, "-VV", "--extra-verbose")) {
- this->ExtraVerbose = true;
- this->Verbose = true;
+ this->Impl->ExtraVerbose = true;
+ this->Impl->Verbose = true;
}
if (this->CheckArgument(arg, "--output-on-failure")) {
- this->OutputTestOutputOnTestFailure = true;
+ this->Impl->OutputTestOutputOnTestFailure = true;
}
if (this->CheckArgument(arg, "--test-output-size-passed") &&
i < args.size() - 1) {
i++;
long outputSize;
if (cmSystemTools::StringToLong(args[i].c_str(), &outputSize)) {
- if (cmCTestTestHandler* pCTestTestHandler =
- static_cast<cmCTestTestHandler*>(this->TestingHandlers["test"])) {
- pCTestTestHandler->SetTestOutputSizePassed(int(outputSize));
- }
+ this->Impl->TestHandler.SetTestOutputSizePassed(int(outputSize));
} else {
cmCTestLog(this, WARNING,
"Invalid value for '--test-output-size-passed': " << args[i]
@@ -1919,10 +1957,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
i++;
long outputSize;
if (cmSystemTools::StringToLong(args[i].c_str(), &outputSize)) {
- if (cmCTestTestHandler* pCTestTestHandler =
- static_cast<cmCTestTestHandler*>(this->TestingHandlers["test"])) {
- pCTestTestHandler->SetTestOutputSizeFailed(int(outputSize));
- }
+ this->Impl->TestHandler.SetTestOutputSizeFailed(int(outputSize));
} else {
cmCTestLog(this, WARNING,
"Invalid value for '--test-output-size-failed': " << args[i]
@@ -1930,10 +1965,10 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
}
}
if (this->CheckArgument(arg, "-N", "--show-only")) {
- this->ShowOnly = true;
+ this->Impl->ShowOnly = true;
}
if (cmSystemTools::StringStartsWith(arg.c_str(), "--show-only=")) {
- this->ShowOnly = true;
+ this->Impl->ShowOnly = true;
// Check if a specific format is requested. Defaults to human readable
// text.
@@ -1941,9 +1976,9 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
std::string format = arg.substr(argWithFormat.length());
if (format == "json-v1") {
// Force quiet mode so the only output is the json object model.
- this->Quiet = true;
- this->OutputAsJson = true;
- this->OutputAsJsonVersion = 1;
+ this->Impl->Quiet = true;
+ this->Impl->OutputAsJson = true;
+ this->Impl->OutputAsJsonVersion = 1;
} else if (format != "human") {
errormsg = "'--show-only=' given unknown value '" + format + "'";
return false;
@@ -1956,25 +1991,25 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
}
if (this->CheckArgument(arg, "--tomorrow-tag")) {
- this->TomorrowTag = true;
+ this->Impl->TomorrowTag = true;
}
if (this->CheckArgument(arg, "--force-new-ctest-process")) {
- this->ForceNewCTestProcess = true;
+ this->Impl->ForceNewCTestProcess = true;
}
if (this->CheckArgument(arg, "-W", "--max-width") && i < args.size() - 1) {
i++;
- this->MaxTestNameWidth = atoi(args[i].c_str());
+ this->Impl->MaxTestNameWidth = atoi(args[i].c_str());
}
if (this->CheckArgument(arg, "--interactive-debug-mode") &&
i < args.size() - 1) {
i++;
- this->InteractiveDebugMode = cmSystemTools::IsOn(args[i]);
+ this->Impl->InteractiveDebugMode = cmSystemTools::IsOn(args[i]);
}
if (this->CheckArgument(arg, "--submit-index") && i < args.size() - 1) {
i++;
- this->SubmitIndex = atoi(args[i].c_str());
- if (this->SubmitIndex < 0) {
- this->SubmitIndex = 0;
+ this->Impl->SubmitIndex = atoi(args[i].c_str());
+ if (this->Impl->SubmitIndex < 0) {
+ this->Impl->SubmitIndex = 0;
}
}
@@ -1983,7 +2018,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
this->AddCTestConfigurationOverwrite(args[i]);
}
if (this->CheckArgument(arg, "-A", "--add-notes") && i < args.size() - 1) {
- this->ProduceXML = true;
+ this->Impl->ProduceXML = true;
this->SetTest("Notes");
i++;
this->SetNotesFiles(args[i].c_str());
@@ -1993,78 +2028,75 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
if (this->CheckArgument(arg, "-I", "--tests-information") &&
i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption("TestsToRunInformation",
- args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("TestsToRunInformation", args[i].c_str());
+ this->GetTestHandler()->SetPersistentOption("TestsToRunInformation",
+ args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption("TestsToRunInformation",
+ args[i].c_str());
}
if (this->CheckArgument(arg, "-U", "--union")) {
- this->GetHandler("test")->SetPersistentOption("UseUnion", "true");
- this->GetHandler("memcheck")->SetPersistentOption("UseUnion", "true");
+ this->GetTestHandler()->SetPersistentOption("UseUnion", "true");
+ this->GetMemCheckHandler()->SetPersistentOption("UseUnion", "true");
}
if (this->CheckArgument(arg, "-R", "--tests-regex") && i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption("IncludeRegularExpression",
- args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("IncludeRegularExpression", args[i].c_str());
+ this->GetTestHandler()->SetPersistentOption("IncludeRegularExpression",
+ args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption("IncludeRegularExpression",
+ args[i].c_str());
}
if (this->CheckArgument(arg, "-L", "--label-regex") && i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption("LabelRegularExpression",
- args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("LabelRegularExpression", args[i].c_str());
+ this->GetTestHandler()->SetPersistentOption("LabelRegularExpression",
+ args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption("LabelRegularExpression",
+ args[i].c_str());
}
if (this->CheckArgument(arg, "-LE", "--label-exclude") &&
i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption(
+ this->GetTestHandler()->SetPersistentOption(
+ "ExcludeLabelRegularExpression", args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption(
"ExcludeLabelRegularExpression", args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("ExcludeLabelRegularExpression", args[i].c_str());
}
if (this->CheckArgument(arg, "-E", "--exclude-regex") &&
i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption("ExcludeRegularExpression",
- args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("ExcludeRegularExpression", args[i].c_str());
+ this->GetTestHandler()->SetPersistentOption("ExcludeRegularExpression",
+ args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption("ExcludeRegularExpression",
+ args[i].c_str());
}
if (this->CheckArgument(arg, "-FA", "--fixture-exclude-any") &&
i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption(
+ this->GetTestHandler()->SetPersistentOption(
+ "ExcludeFixtureRegularExpression", args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption(
"ExcludeFixtureRegularExpression", args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("ExcludeFixtureRegularExpression",
- args[i].c_str());
}
if (this->CheckArgument(arg, "-FS", "--fixture-exclude-setup") &&
i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption(
+ this->GetTestHandler()->SetPersistentOption(
+ "ExcludeFixtureSetupRegularExpression", args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption(
"ExcludeFixtureSetupRegularExpression", args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("ExcludeFixtureSetupRegularExpression",
- args[i].c_str());
}
if (this->CheckArgument(arg, "-FC", "--fixture-exclude-cleanup") &&
i < args.size() - 1) {
i++;
- this->GetHandler("test")->SetPersistentOption(
+ this->GetTestHandler()->SetPersistentOption(
+ "ExcludeFixtureCleanupRegularExpression", args[i].c_str());
+ this->GetMemCheckHandler()->SetPersistentOption(
"ExcludeFixtureCleanupRegularExpression", args[i].c_str());
- this->GetHandler("memcheck")
- ->SetPersistentOption("ExcludeFixtureCleanupRegularExpression",
- args[i].c_str());
}
if (this->CheckArgument(arg, "--rerun-failed")) {
- this->GetHandler("test")->SetPersistentOption("RerunFailed", "true");
- this->GetHandler("memcheck")->SetPersistentOption("RerunFailed", "true");
+ this->GetTestHandler()->SetPersistentOption("RerunFailed", "true");
+ this->GetMemCheckHandler()->SetPersistentOption("RerunFailed", "true");
}
return true;
}
@@ -2111,10 +2143,9 @@ void cmCTest::HandleScriptArguments(size_t& i, std::vector<std::string>& args,
std::string arg = args[i];
if (this->CheckArgument(arg, "-SP", "--script-new-process") &&
i < args.size() - 1) {
- this->RunConfigurationScript = true;
+ this->Impl->RunConfigurationScript = true;
i++;
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+ cmCTestScriptHandler* ch = this->GetScriptHandler();
// -SR is an internal argument, -SP should be ignored when it is passed
if (!SRArgumentSpecified) {
ch->AddConfigurationScript(args[i].c_str(), false);
@@ -2123,18 +2154,16 @@ void cmCTest::HandleScriptArguments(size_t& i, std::vector<std::string>& args,
if (this->CheckArgument(arg, "-SR", "--script-run") && i < args.size() - 1) {
SRArgumentSpecified = true;
- this->RunConfigurationScript = true;
+ this->Impl->RunConfigurationScript = true;
i++;
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+ cmCTestScriptHandler* ch = this->GetScriptHandler();
ch->AddConfigurationScript(args[i].c_str(), true);
}
if (this->CheckArgument(arg, "-S", "--script") && i < args.size() - 1) {
- this->RunConfigurationScript = true;
+ this->Impl->RunConfigurationScript = true;
i++;
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
+ cmCTestScriptHandler* ch = this->GetScriptHandler();
// -SR is an internal argument, -S should be ignored when it is passed
if (!SRArgumentSpecified) {
ch->AddConfigurationScript(args[i].c_str(), true);
@@ -2149,7 +2178,7 @@ bool cmCTest::AddVariableDefinition(const std::string& arg)
cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
if (cmake::ParseCacheEntry(arg, name, value, type)) {
- this->Definitions[name] = value;
+ this->Impl->Definitions[name] = value;
return true;
}
@@ -2165,8 +2194,7 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
bool SRArgumentSpecified = false;
// copy the command line
- this->InitialCommandLineArguments.insert(
- this->InitialCommandLineArguments.end(), args.begin(), args.end());
+ cmAppend(this->Impl->InitialCommandLineArguments, args);
// process the command line arguments
for (size_t i = 1; i < args.size(); ++i) {
@@ -2183,7 +2211,7 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
// --dashboard: handle a request for a dashboard
std::string arg = args[i];
if (this->CheckArgument(arg, "-D", "--dashboard") && i < args.size() - 1) {
- this->ProduceXML = true;
+ this->Impl->ProduceXML = true;
i++;
std::string targ = args[i];
// AddTestsForDashboard parses the dashboard type and converts it
@@ -2219,7 +2247,7 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
// --extra-submit
if (this->CheckArgument(arg, "--extra-submit") && i < args.size() - 1) {
- this->ProduceXML = true;
+ this->Impl->ProduceXML = true;
this->SetTest("Submit");
i++;
if (!this->SubmitExtraFiles(args[i].c_str())) {
@@ -2234,14 +2262,14 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
// --schedule-random
if (this->CheckArgument(arg, "--schedule-random")) {
- this->ScheduleType = "Random";
+ this->Impl->ScheduleType = "Random";
}
// pass the argument to all the handlers as well, but i may no longer be
// set to what it was originally so I'm not sure this is working as
// intended
- for (auto& handler : this->TestingHandlers) {
- if (!handler.second->ProcessCommandLineArguments(arg, i, args)) {
+ for (auto& handler : this->Impl->GetTestingHandlers()) {
+ if (!handler->ProcessCommandLineArguments(arg, i, args)) {
cmCTestLog(this, ERROR_MESSAGE,
"Problem parsing command line arguments within a handler");
return 0;
@@ -2250,7 +2278,7 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
} // the close of the for argument loop
// handle CTEST_PARALLEL_LEVEL environment variable
- if (!this->ParallelLevelSetInCli) {
+ if (!this->Impl->ParallelLevelSetInCli) {
std::string parallel;
if (cmSystemTools::GetEnv("CTEST_PARALLEL_LEVEL", parallel)) {
int plevel = atoi(parallel.c_str());
@@ -2260,10 +2288,10 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
// TestProgressOutput only supported if console supports it and not logging
// to a file
- this->TestProgressOutput = this->TestProgressOutput &&
- !this->OutputLogFile && this->ProgressOutputSupportedByConsole();
+ this->Impl->TestProgressOutput = this->Impl->TestProgressOutput &&
+ !this->Impl->OutputLogFile && this->ProgressOutputSupportedByConsole();
#ifdef _WIN32
- if (this->TestProgressOutput) {
+ if (this->Impl->TestProgressOutput) {
// Disable output line buffering so we can print content without
// a newline.
std::setvbuf(stdout, nullptr, _IONBF, 0);
@@ -2290,7 +2318,7 @@ bool cmCTest::HandleTestActionArgument(const char* ctestExec, size_t& i,
std::string arg = args[i];
if (this->CheckArgument(arg, "-T", "--test-action") &&
(i < args.size() - 1)) {
- this->ProduceXML = true;
+ this->Impl->ProduceXML = true;
i++;
if (!this->SetTest(args[i].c_str(), false)) {
success = false;
@@ -2350,16 +2378,16 @@ int cmCTest::ExecuteTests()
{
int res;
// call process directory
- if (this->RunConfigurationScript) {
- if (this->ExtraVerbose) {
+ if (this->Impl->RunConfigurationScript) {
+ if (this->Impl->ExtraVerbose) {
cmCTestLog(this, OUTPUT, "* Extra verbosity turned on" << std::endl);
}
- for (auto& handler : this->TestingHandlers) {
- handler.second->SetVerbose(this->ExtraVerbose);
- handler.second->SetSubmitIndex(this->SubmitIndex);
+ for (auto& handler : this->Impl->GetTestingHandlers()) {
+ handler->SetVerbose(this->Impl->ExtraVerbose);
+ handler->SetSubmitIndex(this->Impl->SubmitIndex);
}
- this->GetHandler("script")->SetVerbose(this->Verbose);
- res = this->GetHandler("script")->ProcessHandler();
+ this->GetScriptHandler()->SetVerbose(this->Impl->Verbose);
+ res = this->GetScriptHandler()->ProcessHandler();
if (res != 0) {
cmCTestLog(this, DEBUG,
"running script failing returning: " << res << std::endl);
@@ -2368,11 +2396,11 @@ int cmCTest::ExecuteTests()
} else {
// What is this? -V seems to be the same as -VV,
// and Verbose is always on in this case
- this->ExtraVerbose = this->Verbose;
- this->Verbose = true;
- for (auto& handler : this->TestingHandlers) {
- handler.second->SetVerbose(this->Verbose);
- handler.second->SetSubmitIndex(this->SubmitIndex);
+ this->Impl->ExtraVerbose = this->Impl->Verbose;
+ this->Impl->Verbose = true;
+ for (auto& handler : this->Impl->GetTestingHandlers()) {
+ handler->SetVerbose(this->Impl->Verbose);
+ handler->SetSubmitIndex(this->Impl->SubmitIndex);
}
std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
if (!this->Initialize(cwd.c_str(), nullptr)) {
@@ -2393,9 +2421,8 @@ int cmCTest::ExecuteTests()
int cmCTest::RunCMakeAndTest(std::string* output)
{
- this->Verbose = true;
- cmCTestBuildAndTestHandler* handler =
- static_cast<cmCTestBuildAndTestHandler*>(this->GetHandler("buildtest"));
+ this->Impl->Verbose = true;
+ cmCTestBuildAndTestHandler* handler = this->GetBuildAndTestHandler();
int retv = handler->ProcessHandler();
*output = handler->GetOutput();
#ifdef CMAKE_BUILD_WITH_CMAKE
@@ -2413,7 +2440,12 @@ void cmCTest::SetNotesFiles(const char* notes)
if (!notes) {
return;
}
- this->NotesFiles = notes;
+ this->Impl->NotesFiles = notes;
+}
+
+std::chrono::system_clock::time_point cmCTest::GetStopTime() const
+{
+ return this->Impl->StopTime;
}
void cmCTest::SetStopTime(std::string const& time_str)
@@ -2443,21 +2475,29 @@ void cmCTest::SetStopTime(std::string const& time_str)
time_t stop_time = curl_getdate(buf, &current_time);
if (stop_time == -1) {
- this->StopTime = std::chrono::system_clock::time_point();
+ this->Impl->StopTime = std::chrono::system_clock::time_point();
return;
}
- this->StopTime = std::chrono::system_clock::from_time_t(stop_time);
+ this->Impl->StopTime = std::chrono::system_clock::from_time_t(stop_time);
if (stop_time < current_time) {
- this->StopTime += std::chrono::hours(24);
+ this->Impl->StopTime += std::chrono::hours(24);
}
}
+std::string cmCTest::GetScheduleType() const
+{
+ return this->Impl->ScheduleType;
+}
+
+void cmCTest::SetScheduleType(std::string const& type)
+{
+ this->Impl->ScheduleType = type;
+}
+
int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf)
{
bool found = false;
- VectorOfStrings dirs;
- VectorOfStrings ndirs;
cmCTestLog(this, DEBUG,
"* Read custom CTest configuration directory: " << dir
<< std::endl);
@@ -2505,7 +2545,7 @@ int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf)
}
if (found) {
- for (auto& handler : this->TestingHandlers) {
+ for (auto& handler : this->Impl->GetNamedTestingHandlers()) {
cmCTestLog(this, DEBUG,
"* Read custom CTest configuration vectors for handler: "
<< handler.first << " (" << handler.second << ")"
@@ -2596,16 +2636,16 @@ std::string cmCTest::GetShortPathToFile(const char* cfname)
std::string cmCTest::GetCTestConfiguration(const std::string& name)
{
- if (this->CTestConfigurationOverwrites.find(name) !=
- this->CTestConfigurationOverwrites.end()) {
- return this->CTestConfigurationOverwrites[name];
+ if (this->Impl->CTestConfigurationOverwrites.find(name) !=
+ this->Impl->CTestConfigurationOverwrites.end()) {
+ return this->Impl->CTestConfigurationOverwrites[name];
}
- return this->CTestConfiguration[name];
+ return this->Impl->CTestConfiguration[name];
}
void cmCTest::EmptyCTestConfiguration()
{
- this->CTestConfiguration.clear();
+ this->Impl->CTestConfiguration.clear();
}
void cmCTest::SetCTestConfiguration(const char* name, const char* value,
@@ -2620,10 +2660,10 @@ void cmCTest::SetCTestConfiguration(const char* name, const char* value,
return;
}
if (!value) {
- this->CTestConfiguration.erase(name);
+ this->Impl->CTestConfiguration.erase(name);
return;
}
- this->CTestConfiguration[name] = value;
+ this->Impl->CTestConfiguration[name] = value;
}
std::string cmCTest::GetSubmitURL()
@@ -2654,69 +2694,190 @@ std::string cmCTest::GetSubmitURL()
std::string cmCTest::GetCurrentTag()
{
- return this->CurrentTag;
+ return this->Impl->CurrentTag;
}
std::string cmCTest::GetBinaryDir()
{
- return this->BinaryDir;
+ return this->Impl->BinaryDir;
}
std::string const& cmCTest::GetConfigType()
{
- return this->ConfigType;
+ return this->Impl->ConfigType;
+}
+
+cmDuration cmCTest::GetTimeOut() const
+{
+ return this->Impl->TimeOut;
+}
+
+void cmCTest::SetTimeOut(cmDuration t)
+{
+ this->Impl->TimeOut = t;
+}
+
+cmDuration cmCTest::GetGlobalTimeout() const
+{
+ return this->Impl->GlobalTimeout;
}
bool cmCTest::GetShowOnly()
{
- return this->ShowOnly;
+ return this->Impl->ShowOnly;
}
bool cmCTest::GetOutputAsJson()
{
- return this->OutputAsJson;
+ return this->Impl->OutputAsJson;
}
int cmCTest::GetOutputAsJsonVersion()
{
- return this->OutputAsJsonVersion;
+ return this->Impl->OutputAsJsonVersion;
+}
+
+bool cmCTest::ShouldUseHTTP10() const
+{
+ return this->Impl->UseHTTP10;
+}
+
+bool cmCTest::ShouldPrintLabels() const
+{
+ return this->Impl->PrintLabels;
}
int cmCTest::GetMaxTestNameWidth() const
{
- return this->MaxTestNameWidth;
+ return this->Impl->MaxTestNameWidth;
+}
+
+void cmCTest::SetMaxTestNameWidth(int w)
+{
+ this->Impl->MaxTestNameWidth = w;
}
void cmCTest::SetProduceXML(bool v)
{
- this->ProduceXML = v;
+ this->Impl->ProduceXML = v;
}
bool cmCTest::GetProduceXML()
{
- return this->ProduceXML;
+ return this->Impl->ProduceXML;
+}
+
+std::vector<std::string>& cmCTest::GetInitialCommandLineArguments()
+{
+ return this->Impl->InitialCommandLineArguments;
}
const char* cmCTest::GetSpecificTrack()
{
- if (this->SpecificTrack.empty()) {
+ if (this->Impl->SpecificTrack.empty()) {
return nullptr;
}
- return this->SpecificTrack.c_str();
+ return this->Impl->SpecificTrack.c_str();
}
void cmCTest::SetSpecificTrack(const char* track)
{
if (!track) {
- this->SpecificTrack.clear();
+ this->Impl->SpecificTrack.clear();
return;
}
- this->SpecificTrack = track;
+ this->Impl->SpecificTrack = track;
+}
+
+void cmCTest::SetFailover(bool failover)
+{
+ this->Impl->Failover = failover;
+}
+
+bool cmCTest::GetFailover() const
+{
+ return this->Impl->Failover;
+}
+
+bool cmCTest::GetTestProgressOutput() const
+{
+ return this->Impl->TestProgressOutput;
+}
+
+bool cmCTest::GetVerbose() const
+{
+ return this->Impl->Verbose;
+}
+
+bool cmCTest::GetExtraVerbose() const
+{
+ return this->Impl->ExtraVerbose;
+}
+
+void cmCTest::SetStreams(std::ostream* out, std::ostream* err)
+{
+ this->Impl->StreamOut = out;
+ this->Impl->StreamErr = err;
+}
+
+bool cmCTest::GetLabelSummary() const
+{
+ return this->Impl->LabelSummary;
+}
+
+bool cmCTest::GetSubprojectSummary() const
+{
+ return this->Impl->SubprojectSummary;
+}
+
+bool cmCTest::GetOutputTestOutputOnTestFailure() const
+{
+ return this->Impl->OutputTestOutputOnTestFailure;
+}
+
+const std::map<std::string, std::string>& cmCTest::GetDefinitions() const
+{
+ return this->Impl->Definitions;
+}
+
+int cmCTest::GetTestRepeat() const
+{
+ return this->Impl->RepeatTests;
+}
+
+bool cmCTest::GetRepeatUntilFail() const
+{
+ return this->Impl->RepeatUntilFail;
+}
+
+void cmCTest::SetBuildID(const std::string& id)
+{
+ this->Impl->BuildID = id;
+}
+
+std::string cmCTest::GetBuildID() const
+{
+ return this->Impl->BuildID;
}
void cmCTest::AddSubmitFile(Part part, const char* name)
{
- this->Parts[part].SubmitFiles.emplace_back(name);
+ this->Impl->Parts[part].SubmitFiles.emplace_back(name);
+}
+
+std::vector<std::string> const& cmCTest::GetSubmitFiles(Part part) const
+{
+ return this->Impl->Parts[part].SubmitFiles;
+}
+
+void cmCTest::ClearSubmitFiles(Part part)
+{
+ this->Impl->Parts[part].SubmitFiles.clear();
+}
+
+void cmCTest::SetSuppressUpdatingCTestConfiguration(bool val)
+{
+ this->Impl->SuppressUpdatingCTestConfiguration = val;
}
void cmCTest::AddCTestConfigurationOverwrite(const std::string& overStr)
@@ -2732,14 +2893,14 @@ void cmCTest::AddCTestConfigurationOverwrite(const std::string& overStr)
}
std::string key = overStr.substr(0, epos);
std::string value = overStr.substr(epos + 1);
- this->CTestConfigurationOverwrites[key] = value;
+ this->Impl->CTestConfigurationOverwrites[key] = value;
}
void cmCTest::SetConfigType(const char* ct)
{
- this->ConfigType = ct ? ct : "";
- cmSystemTools::ReplaceString(this->ConfigType, ".\\", "");
- std::string confTypeEnv = "CMAKE_CONFIG_TYPE=" + this->ConfigType;
+ this->Impl->ConfigType = ct ? ct : "";
+ cmSystemTools::ReplaceString(this->Impl->ConfigType, ".\\", "");
+ std::string confTypeEnv = "CMAKE_CONFIG_TYPE=" + this->Impl->ConfigType;
cmSystemTools::PutEnv(confTypeEnv);
}
@@ -2776,7 +2937,7 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
stdErr->clear();
cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetCommand(cp, argv.data());
cmsysProcess_SetWorkingDirectory(cp, dir);
if (cmSystemTools::GetRunCommandHideConsole()) {
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
@@ -2796,21 +2957,21 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
res = cmsysProcess_WaitForData(cp, &data, &length, nullptr);
switch (res) {
case cmsysProcess_Pipe_STDOUT:
- tempOutput.insert(tempOutput.end(), data, data + length);
+ cmAppend(tempOutput, data, data + length);
break;
case cmsysProcess_Pipe_STDERR:
- tempError.insert(tempError.end(), data, data + length);
+ cmAppend(tempError, data, data + length);
break;
default:
done = true;
}
if ((res == cmsysProcess_Pipe_STDOUT || res == cmsysProcess_Pipe_STDERR) &&
- this->ExtraVerbose) {
+ this->Impl->ExtraVerbose) {
processOutput.DecodeText(data, length, strdata);
cmSystemTools::Stdout(strdata);
}
}
- if (this->ExtraVerbose) {
+ if (this->Impl->ExtraVerbose) {
processOutput.DecodeText(std::string(), strdata);
if (!strdata.empty()) {
cmSystemTools::Stdout(strdata);
@@ -2820,11 +2981,11 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
cmsysProcess_WaitForExit(cp, nullptr);
if (!tempOutput.empty()) {
processOutput.DecodeText(tempOutput, tempOutput);
- stdOut->append(&*tempOutput.begin(), tempOutput.size());
+ stdOut->append(tempOutput.data(), tempOutput.size());
}
if (!tempError.empty()) {
processOutput.DecodeText(tempError, tempError);
- stdErr->append(&*tempError.begin(), tempError.size());
+ stdErr->append(tempError.data(), tempError.size());
}
bool result = true;
@@ -2859,12 +3020,12 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
void cmCTest::SetOutputLogFileName(const char* name)
{
- if (this->OutputLogFile) {
- delete this->OutputLogFile;
- this->OutputLogFile = nullptr;
+ if (this->Impl->OutputLogFile) {
+ delete this->Impl->OutputLogFile;
+ this->Impl->OutputLogFile = nullptr;
}
if (name) {
- this->OutputLogFile = new cmGeneratedFileStream(name);
+ this->Impl->OutputLogFile = new cmGeneratedFileStream(name);
}
}
@@ -2880,18 +3041,11 @@ static const char* cmCTestStringLogType[] = { "DEBUG",
#define cmCTestLogOutputFileLine(stream) \
do { \
- if (this->ShowLineNumbers) { \
+ if (this->Impl->ShowLineNumbers) { \
(stream) << std::endl << file << ":" << line << " "; \
} \
} while (false)
-void cmCTest::InitStreams()
-{
- // By default we write output to the process output streams.
- this->StreamOut = &std::cout;
- this->StreamErr = &std::cerr;
-}
-
void cmCTest::Log(int logType, const char* file, int line, const char* msg,
bool suppress)
{
@@ -2902,53 +3056,53 @@ void cmCTest::Log(int logType, const char* file, int line, const char* msg,
return;
}
if (logType == cmCTest::HANDLER_PROGRESS_OUTPUT &&
- (this->Debug || this->ExtraVerbose)) {
+ (this->Impl->Debug || this->Impl->ExtraVerbose)) {
return;
}
- if (this->OutputLogFile) {
+ if (this->Impl->OutputLogFile) {
bool display = true;
- if (logType == cmCTest::DEBUG && !this->Debug) {
+ if (logType == cmCTest::DEBUG && !this->Impl->Debug) {
display = false;
}
- if (logType == cmCTest::HANDLER_VERBOSE_OUTPUT && !this->Debug &&
- !this->ExtraVerbose) {
+ if (logType == cmCTest::HANDLER_VERBOSE_OUTPUT && !this->Impl->Debug &&
+ !this->Impl->ExtraVerbose) {
display = false;
}
if (display) {
- cmCTestLogOutputFileLine(*this->OutputLogFile);
- if (logType != this->OutputLogFileLastTag) {
- *this->OutputLogFile << "[";
+ cmCTestLogOutputFileLine(*this->Impl->OutputLogFile);
+ if (logType != this->Impl->OutputLogFileLastTag) {
+ *this->Impl->OutputLogFile << "[";
if (logType >= OTHER || logType < 0) {
- *this->OutputLogFile << "OTHER";
+ *this->Impl->OutputLogFile << "OTHER";
} else {
- *this->OutputLogFile << cmCTestStringLogType[logType];
+ *this->Impl->OutputLogFile << cmCTestStringLogType[logType];
}
- *this->OutputLogFile << "] " << std::endl << std::flush;
+ *this->Impl->OutputLogFile << "] " << std::endl << std::flush;
}
- *this->OutputLogFile << msg << std::flush;
- if (logType != this->OutputLogFileLastTag) {
- *this->OutputLogFile << std::endl << std::flush;
- this->OutputLogFileLastTag = logType;
+ *this->Impl->OutputLogFile << msg << std::flush;
+ if (logType != this->Impl->OutputLogFileLastTag) {
+ *this->Impl->OutputLogFile << std::endl << std::flush;
+ this->Impl->OutputLogFileLastTag = logType;
}
}
}
- if (!this->Quiet) {
- std::ostream& out = *this->StreamOut;
- std::ostream& err = *this->StreamErr;
+ if (!this->Impl->Quiet) {
+ std::ostream& out = *this->Impl->StreamOut;
+ std::ostream& err = *this->Impl->StreamErr;
if (logType == HANDLER_TEST_PROGRESS_OUTPUT) {
- if (this->TestProgressOutput) {
+ if (this->Impl->TestProgressOutput) {
cmCTestLogOutputFileLine(out);
- if (this->FlushTestProgressLine) {
+ if (this->Impl->FlushTestProgressLine) {
printf("\r");
- this->FlushTestProgressLine = false;
+ this->Impl->FlushTestProgressLine = false;
out.flush();
}
std::string msg_str{ msg };
auto const lineBreakIt = msg_str.find('\n');
if (lineBreakIt != std::string::npos) {
- this->FlushTestProgressLine = true;
+ this->Impl->FlushTestProgressLine = true;
msg_str.erase(std::remove(msg_str.begin(), msg_str.end(), '\n'),
msg_str.end());
}
@@ -2965,7 +3119,7 @@ void cmCTest::Log(int logType, const char* file, int line, const char* msg,
switch (logType) {
case DEBUG:
- if (this->Debug) {
+ if (this->Impl->Debug) {
cmCTestLogOutputFileLine(out);
out << msg;
out.flush();
@@ -2973,14 +3127,14 @@ void cmCTest::Log(int logType, const char* file, int line, const char* msg,
break;
case OUTPUT:
case HANDLER_OUTPUT:
- if (this->Debug || this->Verbose) {
+ if (this->Impl->Debug || this->Impl->Verbose) {
cmCTestLogOutputFileLine(out);
out << msg;
out.flush();
}
break;
case HANDLER_VERBOSE_OUTPUT:
- if (this->Debug || this->ExtraVerbose) {
+ if (this->Impl->Debug || this->Impl->ExtraVerbose) {
cmCTestLogOutputFileLine(out);
out << msg;
out.flush();
@@ -3007,7 +3161,7 @@ void cmCTest::Log(int logType, const char* file, int line, const char* msg,
std::string cmCTest::GetColorCode(Color color) const
{
- if (this->OutputColorCode) {
+ if (this->Impl->OutputColorCode) {
#if defined(_WIN32)
// Not supported on Windows
static_cast<void>(color);
@@ -3021,14 +3175,7 @@ std::string cmCTest::GetColorCode(Color color) const
cmDuration cmCTest::GetRemainingTimeAllowed()
{
- if (!this->GetHandler("script")) {
- return cmCTest::MaxDuration();
- }
-
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
-
- return ch->GetRemainingTimeAllowed();
+ return this->GetScriptHandler()->GetRemainingTimeAllowed();
}
cmDuration cmCTest::MaxDuration()
@@ -3038,17 +3185,14 @@ cmDuration cmCTest::MaxDuration()
void cmCTest::SetRunCurrentScript(bool value)
{
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(this->GetHandler("script"));
-
- ch->SetRunCurrentScript(value);
+ this->GetScriptHandler()->SetRunCurrentScript(value);
}
void cmCTest::OutputTestErrors(std::vector<char> const& process_output)
{
std::string test_outputs("\n*** Test Failed:\n");
if (!process_output.empty()) {
- test_outputs.append(&*process_output.begin(), process_output.size());
+ test_outputs.append(process_output.data(), process_output.size());
}
cmCTestLog(this, HANDLER_OUTPUT, test_outputs << std::endl << std::flush);
}
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 92a02c316..d300c33fa 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -10,13 +10,22 @@
#include <chrono>
#include <map>
-#include <set>
+#include <memory> // IWYU pragma: keep
#include <sstream>
#include <string>
#include <time.h>
#include <vector>
-class cmCTestGenericHandler;
+class cmCTestBuildHandler;
+class cmCTestBuildAndTestHandler;
+class cmCTestCoverageHandler;
+class cmCTestScriptHandler;
+class cmCTestTestHandler;
+class cmCTestUpdateHandler;
+class cmCTestConfigureHandler;
+class cmCTestMemCheckHandler;
+class cmCTestSubmitHandler;
+class cmCTestUploadHandler;
class cmCTestStartCommand;
class cmGeneratedFileStream;
class cmMakefile;
@@ -31,9 +40,6 @@ class cmXMLWriter;
*/
class cmCTest
{
- friend class cmCTestRunTest;
- friend class cmCTestMultiProcessHandler;
-
public:
typedef cmProcessOutput::Encoding Encoding;
/** Enumerate parts of the testing and submission process. */
@@ -54,44 +60,10 @@ public:
PartCount // Update names in constructor when adding a part
};
- /** Representation of one part. */
- struct PartInfo
- {
- void SetName(const std::string& name) { this->Name = name; }
- const std::string& GetName() const { return this->Name; }
-
- void Enable() { this->Enabled = true; }
- explicit operator bool() const { return this->Enabled; }
-
- std::vector<std::string> SubmitFiles;
-
- private:
- bool Enabled = false;
- std::string Name;
- };
-#ifdef CMAKE_BUILD_WITH_CMAKE
- enum HTTPMethod
- {
- HTTP_GET,
- HTTP_POST,
- HTTP_PUT
- };
-
- /**
- * Perform an HTTP request.
- */
- static int HTTPRequest(std::string url, HTTPMethod method,
- std::string& response, std::string const& fields = "",
- std::string const& putFile = "", int timeout = 0);
-#endif
-
/** Get a testing part id from its string name. Returns PartCount
if the string does not name a valid part. */
Part GetPartFromName(const char* name);
- typedef std::vector<std::string> VectorOfStrings;
- typedef std::set<std::string> SetOfStrings;
-
/** Process Command line arguments */
int Run(std::vector<std::string>&, std::string* output = nullptr);
@@ -128,7 +100,7 @@ public:
/**
* Is the tomorrow tag set?
*/
- bool GetTomorrowTag() { return this->TomorrowTag; }
+ bool GetTomorrowTag() const;
/**
* Try to run tests of the project
@@ -137,16 +109,16 @@ public:
/** what is the configuration type, e.g. Debug, Release etc. */
std::string const& GetConfigType();
- cmDuration GetTimeOut() { return this->TimeOut; }
- void SetTimeOut(cmDuration t) { this->TimeOut = t; }
+ cmDuration GetTimeOut() const;
+ void SetTimeOut(cmDuration t);
- cmDuration GetGlobalTimeout() { return this->GlobalTimeout; }
+ cmDuration GetGlobalTimeout() const;
/** how many test to run at the same time */
- int GetParallelLevel() { return this->ParallelLevel; }
+ int GetParallelLevel() const;
void SetParallelLevel(int);
- unsigned long GetTestLoad() { return this->TestLoad; }
+ unsigned long GetTestLoad() const;
void SetTestLoad(unsigned long);
/**
@@ -164,7 +136,7 @@ public:
* Set the cmake test mode (experimental, nightly, continuous).
*/
void SetTestModel(int mode);
- int GetTestModel() { return this->TestModel; }
+ int GetTestModel() const;
std::string GetTestModelString();
static int GetTestModelFromString(const char* str);
@@ -182,6 +154,9 @@ public:
cmCTest();
~cmCTest();
+ cmCTest(const cmCTest&) = delete;
+ cmCTest& operator=(const cmCTest&) = delete;
+
/** Set the notes files to be created. */
void SetNotesFiles(const char* notes);
@@ -219,26 +194,23 @@ public:
int GetOutputAsJsonVersion();
- bool ShouldUseHTTP10() { return this->UseHTTP10; }
+ bool ShouldUseHTTP10() const;
- bool ShouldPrintLabels() { return this->PrintLabels; }
+ bool ShouldPrintLabels() const;
bool ShouldCompressTestOutput();
bool CompressString(std::string& str);
- std::chrono::system_clock::time_point GetStopTime()
- {
- return this->StopTime;
- }
+ std::chrono::system_clock::time_point GetStopTime() const;
void SetStopTime(std::string const& time);
/** Used for parallel ctest job scheduling */
- std::string GetScheduleType() { return this->ScheduleType; }
- void SetScheduleType(std::string const& type) { this->ScheduleType = type; }
+ std::string GetScheduleType() const;
+ void SetScheduleType(std::string const& type);
/** The max output width */
int GetMaxTestNameWidth() const;
- void SetMaxTestNameWidth(int w) { this->MaxTestNameWidth = w; }
+ void SetMaxTestNameWidth(int w);
/**
* Run a single executable command and put the stdout and stderr
@@ -277,8 +249,9 @@ public:
* Run command specialized for make and configure. Returns process status
* and retVal is return value or exception.
*/
- int RunMakeCommand(const char* command, std::string& output, int* retVal,
- const char* dir, cmDuration timeout, std::ostream& ofs,
+ int RunMakeCommand(const std::string& command, std::string& output,
+ int* retVal, const char* dir, cmDuration timeout,
+ std::ostream& ofs,
Encoding encoding = cmProcessOutput::Auto);
/** Return the current tag */
@@ -331,16 +304,18 @@ public:
Encoding encoding = cmProcessOutput::Auto);
/**
- * Execute handler and return its result. If the handler fails, it returns
- * negative value.
- */
- int ExecuteHandler(const char* handler);
-
- /**
* Get the handler object
*/
- cmCTestGenericHandler* GetHandler(const char* handler);
- cmCTestGenericHandler* GetInitializedHandler(const char* handler);
+ cmCTestBuildHandler* GetBuildHandler();
+ cmCTestBuildAndTestHandler* GetBuildAndTestHandler();
+ cmCTestCoverageHandler* GetCoverageHandler();
+ cmCTestScriptHandler* GetScriptHandler();
+ cmCTestTestHandler* GetTestHandler();
+ cmCTestUpdateHandler* GetUpdateHandler();
+ cmCTestConfigureHandler* GetConfigureHandler();
+ cmCTestMemCheckHandler* GetMemCheckHandler();
+ cmCTestSubmitHandler* GetSubmitHandler();
+ cmCTestUploadHandler* GetUploadHandler();
/**
* Set the CTest variable from CMake variable
@@ -350,9 +325,6 @@ public:
const std::string& cmake_var,
bool suppress = false);
- /** Make string safe to be sent as a URL */
- static std::string MakeURLSafe(const std::string&);
-
/** Decode a URL to the original string. */
static std::string DecodeURL(const std::string&);
@@ -360,10 +332,7 @@ public:
* Should ctect configuration be updated. When using new style ctest
* script, this should be true.
*/
- void SetSuppressUpdatingCTestConfiguration(bool val)
- {
- this->SuppressUpdatingCTestConfiguration = val;
- }
+ void SetSuppressUpdatingCTestConfiguration(bool val);
/**
* Add overwrite to ctest configuration.
@@ -373,14 +342,14 @@ public:
void AddCTestConfigurationOverwrite(const std::string& encstr);
/** Create XML file that contains all the notes specified */
- int GenerateNotesFile(const VectorOfStrings& files);
+ int GenerateNotesFile(std::vector<std::string> const& files);
/** Create XML file to indicate that build is complete */
int GenerateDoneFile();
/** Submit extra files to the server */
bool SubmitExtraFiles(const char* files);
- bool SubmitExtraFiles(const VectorOfStrings& files);
+ bool SubmitExtraFiles(std::vector<std::string> const& files);
/** Set the output log file name */
void SetOutputLogFileName(const char* name);
@@ -420,62 +389,52 @@ public:
std::string GetColorCode(Color color) const;
/** The Build ID is assigned by CDash */
- void SetBuildID(const std::string& id) { this->BuildID = id; }
- std::string GetBuildID() { return this->BuildID; }
+ void SetBuildID(const std::string& id);
+ std::string GetBuildID() const;
/** Add file to be submitted */
void AddSubmitFile(Part part, const char* name);
- std::vector<std::string> const& GetSubmitFiles(Part part)
- {
- return this->Parts[part].SubmitFiles;
- }
- void ClearSubmitFiles(Part part) { this->Parts[part].SubmitFiles.clear(); }
+ std::vector<std::string> const& GetSubmitFiles(Part part) const;
+ void ClearSubmitFiles(Part part);
/**
* Read the custom configuration files and apply them to the current ctest
*/
int ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf);
- std::vector<std::string>& GetInitialCommandLineArguments()
- {
- return this->InitialCommandLineArguments;
- }
+ std::vector<std::string>& GetInitialCommandLineArguments();
/** Set the track to submit to */
void SetSpecificTrack(const char* track);
const char* GetSpecificTrack();
- void SetFailover(bool failover) { this->Failover = failover; }
- bool GetFailover() { return this->Failover; }
+ void SetFailover(bool failover);
+ bool GetFailover() const;
- bool GetTestProgressOutput() const { return this->TestProgressOutput; }
+ bool GetTestProgressOutput() const;
- bool GetVerbose() { return this->Verbose; }
- bool GetExtraVerbose() { return this->ExtraVerbose; }
+ bool GetVerbose() const;
+ bool GetExtraVerbose() const;
/** Direct process output to given streams. */
- void SetStreams(std::ostream* out, std::ostream* err)
- {
- this->StreamOut = out;
- this->StreamErr = err;
- }
+ void SetStreams(std::ostream* out, std::ostream* err);
+
void AddSiteProperties(cmXMLWriter& xml);
- bool GetLabelSummary() { return this->LabelSummary; }
- bool GetSubprojectSummary() { return this->SubprojectSummary; }
+ bool GetLabelSummary() const;
+ bool GetSubprojectSummary() const;
std::string GetCostDataFile();
- const std::map<std::string, std::string>& GetDefinitions()
- {
- return this->Definitions;
- }
+ bool GetOutputTestOutputOnTestFailure() const;
+
+ const std::map<std::string, std::string>& GetDefinitions() const;
/** Return the number of times a test should be run */
- int GetTestRepeat() { return this->RepeatTests; }
+ int GetTestRepeat() const;
/** Return true if test should run until fail */
- bool GetRepeatUntilFail() { return this->RepeatUntilFail; }
+ bool GetRepeatUntilFail() const;
void GenerateSubprojectsOutput(cmXMLWriter& xml);
std::vector<std::string> GetLabelsForSubprojects();
@@ -483,85 +442,8 @@ public:
void SetRunCurrentScript(bool value);
private:
- int RepeatTests;
- bool RepeatUntilFail;
- std::string ConfigType;
- std::string ScheduleType;
- std::chrono::system_clock::time_point StopTime;
- bool TestProgressOutput;
- bool Verbose;
- bool ExtraVerbose;
- bool ProduceXML;
- bool LabelSummary;
- bool SubprojectSummary;
- bool UseHTTP10;
- bool PrintLabels;
- bool Failover;
-
- bool FlushTestProgressLine;
-
- bool ForceNewCTestProcess;
-
- bool RunConfigurationScript;
-
int GenerateNotesFile(const char* files);
- // these are helper classes
- typedef std::map<std::string, cmCTestGenericHandler*> t_TestingHandlers;
- t_TestingHandlers TestingHandlers;
-
- bool ShowOnly;
- bool OutputAsJson;
- int OutputAsJsonVersion;
-
- /** Map of configuration properties */
- typedef std::map<std::string, std::string> CTestConfigurationMap;
-
- // TODO: The ctest configuration should be a hierarchy of
- // configuration option sources: command-line, script, ini file.
- // Then the ini file can get re-loaded whenever it changes without
- // affecting any higher-precedence settings.
- CTestConfigurationMap CTestConfiguration;
- CTestConfigurationMap CTestConfigurationOverwrites;
- PartInfo Parts[PartCount];
- typedef std::map<std::string, Part> PartMapType;
- PartMapType PartMap;
-
- std::string CurrentTag;
- bool TomorrowTag;
-
- int TestModel;
- std::string SpecificTrack;
-
- cmDuration TimeOut;
-
- cmDuration GlobalTimeout;
-
- int MaxTestNameWidth;
-
- int ParallelLevel;
- bool ParallelLevelSetInCli;
-
- unsigned long TestLoad;
-
- int CompatibilityMode;
-
- // information for the --build-and-test options
- std::string BinaryDir;
-
- std::string NotesFiles;
-
- bool InteractiveDebugMode;
-
- bool ShortDateFormat;
-
- bool CompressXMLFiles;
- bool CompressTestOutput;
-
- void InitStreams();
- std::ostream* StreamOut;
- std::ostream* StreamErr;
-
void BlockTestErrorDiagnostics();
/**
@@ -606,7 +488,8 @@ private:
bool UpdateCTestConfiguration();
/** Create note from files. */
- int GenerateCTestNotesOutput(cmXMLWriter& xml, const VectorOfStrings& files);
+ int GenerateCTestNotesOutput(cmXMLWriter& xml,
+ std::vector<std::string> const& files);
/** Check if the argument is the one specified */
bool CheckArgument(const std::string& arg, const char* varg1,
@@ -626,25 +509,8 @@ private:
int RunCMakeAndTest(std::string* output);
int ExecuteTests();
- bool SuppressUpdatingCTestConfiguration;
-
- bool Debug;
- bool ShowLineNumbers;
- bool Quiet;
-
- std::string BuildID;
-
- std::vector<std::string> InitialCommandLineArguments;
-
- int SubmitIndex;
-
- cmGeneratedFileStream* OutputLogFile;
- int OutputLogFileLastTag;
-
- bool OutputTestOutputOnTestFailure;
- bool OutputColorCode;
-
- std::map<std::string, std::string> Definitions;
+ struct Private;
+ std::unique_ptr<Private> Impl;
};
class cmCTestLogWrite
diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx
index 2728f0f9a..358f095bb 100644
--- a/Source/cmCacheManager.cxx
+++ b/Source/cmCacheManager.cxx
@@ -239,8 +239,7 @@ bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger)
cmGeneratedFileStream fout(cacheFile);
fout.SetCopyIfDifferent(true);
if (!fout) {
- cmSystemTools::Error("Unable to open cache file for save. ",
- cacheFile.c_str());
+ cmSystemTools::Error("Unable to open cache file for save. " + cacheFile);
cmSystemTools::ReportLastSystemError("");
return false;
}
@@ -309,8 +308,7 @@ bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger)
if (!ce.Initialized) {
/*
// This should be added in, but is not for now.
- cmSystemTools::Error("Cache entry \"", (*i).first.c_str(),
- "\" is uninitialized");
+ cmSystemTools::Error("Cache entry \"" + i.first + "\" is uninitialized");
*/
} else if (t != cmStateEnums::INTERNAL) {
// Format is key:type=value
@@ -364,8 +362,8 @@ bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger)
checkCacheFile += "/cmake.check_cache";
cmsys::ofstream checkCache(checkCacheFile.c_str());
if (!checkCache) {
- cmSystemTools::Error("Unable to open check cache file for write. ",
- checkCacheFile.c_str());
+ cmSystemTools::Error("Unable to open check cache file for write. " +
+ checkCacheFile);
return false;
}
checkCache << "# This file is generated by cmake for dependency checking "
diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h
index 0c70ed27f..65f22f72b 100644
--- a/Source/cmCacheManager.h
+++ b/Source/cmCacheManager.h
@@ -93,33 +93,33 @@ public:
CacheEntry& GetEntry() { return this->Position->second; }
};
- ///! return an iterator to iterate through the cache map
+ //! return an iterator to iterate through the cache map
cmCacheManager::CacheIterator NewIterator() { return CacheIterator(*this); }
- ///! Load a cache for given makefile. Loads from path/CMakeCache.txt.
+ //! Load a cache for given makefile. Loads from path/CMakeCache.txt.
bool LoadCache(const std::string& path, bool internal,
std::set<std::string>& excludes,
std::set<std::string>& includes);
- ///! Save cache for given makefile. Saves to output path/CMakeCache.txt
+ //! Save cache for given makefile. Saves to output path/CMakeCache.txt
bool SaveCache(const std::string& path, cmMessenger* messenger);
- ///! Delete the cache given
+ //! Delete the cache given
bool DeleteCache(const std::string& path);
- ///! Print the cache to a stream
+ //! Print the cache to a stream
void PrintCache(std::ostream&) const;
- ///! Get the iterator for an entry with a given key.
+ //! Get the iterator for an entry with a given key.
cmCacheManager::CacheIterator GetCacheIterator(const char* key = nullptr);
- ///! Remove an entry from the cache
+ //! Remove an entry from the cache
void RemoveCacheEntry(const std::string& key);
- ///! Get the number of entries in the cache
+ //! Get the number of entries in the cache
int GetSize() { return static_cast<int>(this->Cache.size()); }
- ///! Get a value from the cache given a key
+ //! Get a value from the cache given a key
const std::string* GetInitializedCacheValue(const std::string& key) const;
const char* GetCacheEntryValue(const std::string& key)
@@ -197,14 +197,14 @@ public:
unsigned int GetCacheMinorVersion() const { return this->CacheMinorVersion; }
protected:
- ///! Add an entry into the cache
+ //! Add an entry into the cache
void AddCacheEntry(const std::string& key, const char* value,
const char* helpString,
cmStateEnums::CacheEntryType type);
- ///! Get a cache entry object for a key
+ //! Get a cache entry object for a key
CacheEntry* GetCacheEntry(const std::string& key);
- ///! Clean out the CMakeFiles directory if no CMakeCache.txt
+ //! Clean out the CMakeFiles directory if no CMakeCache.txt
void CleanCMakeFiles(const std::string& path);
// Cache version info
diff --git a/Source/cmCallVisualStudioMacro.cxx b/Source/cmCallVisualStudioMacro.cxx
index ee5feee76..f7a224492 100644
--- a/Source/cmCallVisualStudioMacro.cxx
+++ b/Source/cmCallVisualStudioMacro.cxx
@@ -35,8 +35,8 @@ static bool LogErrorsAsMessages;
# endif
# endif
-///! Use ReportHRESULT to make a cmSystemTools::Message after calling
-///! a COM method that may have failed.
+//! Use ReportHRESULT to make a cmSystemTools::Message after calling
+//! a COM method that may have failed.
# define ReportHRESULT(hr, context) \
if (FAILED(hr)) { \
if (LogErrorsAsMessages) { \
@@ -50,7 +50,7 @@ static bool LogErrorsAsMessages;
} \
}
-///! Using the given instance of Visual Studio, call the named macro
+//! Using the given instance of Visual Studio, call the named macro
HRESULT InstanceCallMacro(IDispatch* vsIDE, const std::string& macro,
const std::string& args)
{
@@ -61,7 +61,8 @@ HRESULT InstanceCallMacro(IDispatch* vsIDE, const std::string& macro,
if (0 != vsIDE) {
DISPID dispid = (DISPID)-1;
- OLECHAR* name = L"ExecuteCommand";
+ wchar_t execute_command[] = L"ExecuteCommand";
+ OLECHAR* name = execute_command;
hr =
vsIDE->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
@@ -119,7 +120,8 @@ HRESULT InstanceCallMacro(IDispatch* vsIDE, const std::string& macro,
}
oss << " dwHelpContext: " << excep.dwHelpContext << std::endl;
oss << " pvReserved: " << excep.pvReserved << std::endl;
- oss << " pfnDeferredFillIn: " << excep.pfnDeferredFillIn << std::endl;
+ oss << " pfnDeferredFillIn: "
+ << reinterpret_cast<void*>(excep.pfnDeferredFillIn) << std::endl;
oss << " scode: " << excep.scode << std::endl;
}
@@ -133,14 +135,15 @@ HRESULT InstanceCallMacro(IDispatch* vsIDE, const std::string& macro,
return hr;
}
-///! Get the Solution object from the IDE object
+//! Get the Solution object from the IDE object
HRESULT GetSolutionObject(IDispatch* vsIDE, IDispatchPtr& vsSolution)
{
HRESULT hr = E_POINTER;
if (0 != vsIDE) {
DISPID dispid = (DISPID)-1;
- OLECHAR* name = L"Solution";
+ wchar_t solution[] = L"Solution";
+ OLECHAR* name = solution;
hr =
vsIDE->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
@@ -176,14 +179,15 @@ HRESULT GetSolutionObject(IDispatch* vsIDE, IDispatchPtr& vsSolution)
return hr;
}
-///! Get the FullName property from the Solution object
+//! Get the FullName property from the Solution object
HRESULT GetSolutionFullName(IDispatch* vsSolution, std::string& fullName)
{
HRESULT hr = E_POINTER;
if (0 != vsSolution) {
DISPID dispid = (DISPID)-1;
- OLECHAR* name = L"FullName";
+ wchar_t full_name[] = L"FullName";
+ OLECHAR* name = full_name;
hr = vsSolution->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT,
&dispid);
@@ -220,7 +224,7 @@ HRESULT GetSolutionFullName(IDispatch* vsSolution, std::string& fullName)
return hr;
}
-///! Get the FullName property from the Solution object, given the IDE object
+//! Get the FullName property from the Solution object, given the IDE object
HRESULT GetIDESolutionFullName(IDispatch* vsIDE, std::string& fullName)
{
IDispatchPtr vsSolution;
@@ -235,8 +239,8 @@ HRESULT GetIDESolutionFullName(IDispatch* vsIDE, std::string& fullName)
return hr;
}
-///! Get all running objects from the Windows running object table.
-///! Save them in a map by their display names.
+//! Get all running objects from the Windows running object table.
+//! Save them in a map by their display names.
HRESULT GetRunningInstances(std::map<std::string, IUnknownPtr>& mrot)
{
// mrot == Map of the Running Object Table
@@ -292,8 +296,8 @@ HRESULT GetRunningInstances(std::map<std::string, IUnknownPtr>& mrot)
return hr;
}
-///! Do the two file names refer to the same Visual Studio solution? Or are
-///! we perhaps looking for any and all solutions?
+//! Do the two file names refer to the same Visual Studio solution? Or are
+//! we perhaps looking for any and all solutions?
bool FilesSameSolution(const std::string& slnFile, const std::string& slnName)
{
if (slnFile == "ALL" || slnName == "ALL") {
@@ -310,9 +314,9 @@ bool FilesSameSolution(const std::string& slnFile, const std::string& slnName)
return s1 == s2;
}
-///! Find instances of Visual Studio with the given solution file
-///! open. Pass "ALL" for slnFile to gather all running instances
-///! of Visual Studio.
+//! Find instances of Visual Studio with the given solution file
+//! open. Pass "ALL" for slnFile to gather all running instances
+//! of Visual Studio.
HRESULT FindVisualStudioInstances(const std::string& slnFile,
std::vector<IDispatchPtr>& instances)
{
@@ -384,8 +388,8 @@ int cmCallVisualStudioMacro::GetNumberOfRunningVisualStudioInstances(
return count;
}
-///! Get all running objects from the Windows running object table.
-///! Save them in a map by their display names.
+//! Get all running objects from the Windows running object table.
+//! Save them in a map by their display names.
int cmCallVisualStudioMacro::CallMacro(const std::string& slnFile,
const std::string& macro,
const std::string& args,
diff --git a/Source/cmCallVisualStudioMacro.h b/Source/cmCallVisualStudioMacro.h
index fdc9e6646..9b5b3a843 100644
--- a/Source/cmCallVisualStudioMacro.h
+++ b/Source/cmCallVisualStudioMacro.h
@@ -16,16 +16,16 @@
class cmCallVisualStudioMacro
{
public:
- ///! Call the named macro in instances of Visual Studio with the
- ///! given solution file open. Pass "ALL" for slnFile to call the
- ///! macro in each Visual Studio instance.
+ //! Call the named macro in instances of Visual Studio with the
+ //! given solution file open. Pass "ALL" for slnFile to call the
+ //! macro in each Visual Studio instance.
static int CallMacro(const std::string& slnFile, const std::string& macro,
const std::string& args,
const bool logErrorsAsMessages);
- ///! Count the number of running instances of Visual Studio with the
- ///! given solution file open. Pass "ALL" for slnFile to count all
- ///! running Visual Studio instances.
+ //! Count the number of running instances of Visual Studio with the
+ //! given solution file open. Pass "ALL" for slnFile to count all
+ //! running Visual Studio instances.
static int GetNumberOfRunningVisualStudioInstances(
const std::string& slnFile);
diff --git a/Source/cmCommandArgumentsHelper.cxx b/Source/cmCommandArgumentsHelper.cxx
deleted file mode 100644
index 968b17cb9..000000000
--- a/Source/cmCommandArgumentsHelper.cxx
+++ /dev/null
@@ -1,233 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmCommandArgumentsHelper.h"
-
-cmCommandArgument::cmCommandArgument(cmCommandArgumentsHelper* args,
- const char* key,
- cmCommandArgumentGroup* group)
- : Key(key)
- , Group(group)
- , WasActive(false)
- , ArgumentsBeforeEmpty(true)
- , CurrentIndex(0)
-{
- if (args != nullptr) {
- args->AddArgument(this);
- }
-
- if (this->Group != nullptr) {
- this->Group->ContainedArguments.push_back(this);
- }
-}
-
-void cmCommandArgument::Reset()
-{
- this->WasActive = false;
- this->CurrentIndex = 0;
- this->DoReset();
-}
-
-void cmCommandArgument::Follows(const cmCommandArgument* arg)
-{
- this->ArgumentsBeforeEmpty = false;
- this->ArgumentsBefore.insert(arg);
-}
-
-void cmCommandArgument::FollowsGroup(const cmCommandArgumentGroup* group)
-{
- if (group != nullptr) {
- this->ArgumentsBeforeEmpty = false;
- this->ArgumentsBefore.insert(group->ContainedArguments.begin(),
- group->ContainedArguments.end());
- }
-}
-
-bool cmCommandArgument::MayFollow(const cmCommandArgument* current) const
-{
- if (this->ArgumentsBeforeEmpty) {
- return true;
- }
- return this->ArgumentsBefore.find(current) != this->ArgumentsBefore.end();
-}
-
-bool cmCommandArgument::KeyMatches(const std::string& key) const
-{
- if ((this->Key == nullptr) || (this->Key[0] == '\0')) {
- return true;
- }
- return (key == this->Key);
-}
-
-void cmCommandArgument::ApplyOwnGroup()
-{
- if (this->Group != nullptr) {
- for (cmCommandArgument* cargs : this->Group->ContainedArguments) {
- if (cargs != this) {
- this->ArgumentsBefore.insert(cargs);
- }
- }
- }
-}
-
-void cmCommandArgument::Activate()
-{
- this->WasActive = true;
- this->CurrentIndex = 0;
-}
-
-bool cmCommandArgument::Consume(const std::string& arg)
-{
- bool res = this->DoConsume(arg, this->CurrentIndex);
- this->CurrentIndex++;
- return res;
-}
-
-cmCAStringVector::cmCAStringVector(cmCommandArgumentsHelper* args,
- const char* key,
- cmCommandArgumentGroup* group)
- : cmCommandArgument(args, key, group)
- , Ignore(nullptr)
-{
- if ((key == nullptr) || (*key == 0)) {
- this->DataStart = 0;
- } else {
- this->DataStart = 1;
- }
-}
-
-bool cmCAStringVector::DoConsume(const std::string& arg, unsigned int index)
-{
- if (index >= this->DataStart) {
- if ((this->Ignore == nullptr) || (arg != this->Ignore)) {
- this->Vector.push_back(arg);
- }
- }
-
- return false;
-}
-
-void cmCAStringVector::DoReset()
-{
- this->Vector.clear();
-}
-
-cmCAString::cmCAString(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group)
- : cmCommandArgument(args, key, group)
-{
- if ((key == nullptr) || (*key == 0)) {
- this->DataStart = 0;
- } else {
- this->DataStart = 1;
- }
-}
-
-bool cmCAString::DoConsume(const std::string& arg, unsigned int index)
-{
- if (index == this->DataStart) {
- this->String = arg;
- }
-
- return index >= this->DataStart;
-}
-
-void cmCAString::DoReset()
-{
- this->String.clear();
-}
-
-cmCAEnabler::cmCAEnabler(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group)
- : cmCommandArgument(args, key, group)
- , Enabled(false)
-{
-}
-
-bool cmCAEnabler::DoConsume(const std::string&, unsigned int index)
-{
- if (index == 0) {
- this->Enabled = true;
- }
- return true;
-}
-
-void cmCAEnabler::DoReset()
-{
- this->Enabled = false;
-}
-
-cmCADisabler::cmCADisabler(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group)
- : cmCommandArgument(args, key, group)
- , Enabled(true)
-{
-}
-
-bool cmCADisabler::DoConsume(const std::string&, unsigned int index)
-{
- if (index == 0) {
- this->Enabled = false;
- }
- return true;
-}
-
-void cmCADisabler::DoReset()
-{
- this->Enabled = true;
-}
-
-void cmCommandArgumentGroup::Follows(const cmCommandArgument* arg)
-{
- for (cmCommandArgument* ca : this->ContainedArguments) {
- ca->Follows(arg);
- }
-}
-
-void cmCommandArgumentGroup::FollowsGroup(const cmCommandArgumentGroup* group)
-{
- for (cmCommandArgument* ca : this->ContainedArguments) {
- ca->FollowsGroup(group);
- }
-}
-
-void cmCommandArgumentsHelper::Parse(const std::vector<std::string>* args,
- std::vector<std::string>* unconsumedArgs)
-{
- if (args == nullptr) {
- return;
- }
-
- for (cmCommandArgument* ca : this->Arguments) {
- ca->ApplyOwnGroup();
- ca->Reset();
- }
-
- cmCommandArgument* activeArgument = nullptr;
- const cmCommandArgument* previousArgument = nullptr;
- for (std::string const& it : *args) {
- for (cmCommandArgument* ca : this->Arguments) {
- if (ca->KeyMatches(it) && (ca->MayFollow(previousArgument))) {
- activeArgument = ca;
- activeArgument->Activate();
- break;
- }
- }
-
- if (activeArgument) {
- bool argDone = activeArgument->Consume(it);
- previousArgument = activeArgument;
- if (argDone) {
- activeArgument = nullptr;
- }
- } else {
- if (unconsumedArgs != nullptr) {
- unconsumedArgs->push_back(it);
- }
- }
- }
-}
-
-void cmCommandArgumentsHelper::AddArgument(cmCommandArgument* arg)
-{
- this->Arguments.push_back(arg);
-}
diff --git a/Source/cmCommandArgumentsHelper.h b/Source/cmCommandArgumentsHelper.h
deleted file mode 100644
index dc934bed6..000000000
--- a/Source/cmCommandArgumentsHelper.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#ifndef cmCommandArgumentsHelper_h
-#define cmCommandArgumentsHelper_h
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <set>
-#include <string>
-#include <vector>
-
-class cmCommandArgumentGroup;
-class cmCommandArgumentsHelper;
-
-/* cmCommandArgumentsHelper, cmCommandArgumentGroup and cmCommandArgument (i.e.
-its derived classes cmCAXXX can be used to simplify the processing of
-arguments to cmake commands. Maybe they can also be used to generate
-documentation.
-
-For every argument supported by a command one cmCommandArgument is created
-and added to cmCommandArgumentsHelper. cmCommand has a cmCommandArgumentsHelper
-as member variable so this should be used.
-
-The order of the arguments is defined using the Follows(arg) method. It says
-that this argument follows immediateley the given argument. It can be used
-with multiple arguments if the argument can follow after different arguments.
-
-Arguments can be arranged in groups using cmCommandArgumentGroup. Every
-member of a group can follow any other member of the group. These groups
-can also be used to define the order.
-
-Once all arguments and groups are set up, cmCommandArgumentsHelper::Parse()
-is called and afterwards the values of the arguments can be evaluated.
-
-For an example see cmExportCommand.cxx.
-*/
-class cmCommandArgument
-{
-public:
- cmCommandArgument(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group = nullptr);
- virtual ~cmCommandArgument() = default;
-
- /// this argument may follow after arg. 0 means it comes first.
- void Follows(const cmCommandArgument* arg);
-
- /// this argument may follow after any of the arguments in the given group
- void FollowsGroup(const cmCommandArgumentGroup* group);
-
- /// Returns true if the argument was found in the argument list
- bool WasFound() const { return this->WasActive; }
-
- // The following methods are only called from
- // cmCommandArgumentsHelper::Parse(), but making this a friend would
- // give it access to everything
-
- /// Make the current argument the currently active argument
- void Activate();
- /// Consume the current string
- bool Consume(const std::string& arg);
-
- /// Return true if this argument may follow after the given argument.
- bool MayFollow(const cmCommandArgument* current) const;
-
- /** Returns true if the given key matches the key for this argument.
- If this argument has an empty key everything matches. */
- bool KeyMatches(const std::string& key) const;
-
- /// Make this argument follow all members of the own group
- void ApplyOwnGroup();
-
- /// Reset argument, so it's back to its initial state
- void Reset();
-
-private:
- const char* Key;
- std::set<const cmCommandArgument*> ArgumentsBefore;
- cmCommandArgumentGroup* Group;
- bool WasActive;
- bool ArgumentsBeforeEmpty;
- unsigned int CurrentIndex;
-
- virtual bool DoConsume(const std::string& arg, unsigned int index) = 0;
- virtual void DoReset() = 0;
-};
-
-/** cmCAStringVector is to be used for arguments which can consist of more
-than one string, e.g. the FILES argument in INSTALL(FILES f1 f2 f3 ...). */
-class cmCAStringVector : public cmCommandArgument
-{
-public:
- cmCAStringVector(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group = nullptr);
-
- /// Return the vector of strings
- const std::vector<std::string>& GetVector() const { return this->Vector; }
-
- /** Is there a keyword which should be skipped in
- the arguments (e.g. ARGS for ADD_CUSTOM_COMMAND) ? */
- void SetIgnore(const char* ignore) { this->Ignore = ignore; }
-
-private:
- std::vector<std::string> Vector;
- unsigned int DataStart;
- const char* Ignore;
- bool DoConsume(const std::string& arg, unsigned int index) override;
- void DoReset() override;
-};
-
-/** cmCAString is to be used for arguments which consist of one value,
-e.g. the executable name in ADD_EXECUTABLE(). */
-class cmCAString : public cmCommandArgument
-{
-public:
- cmCAString(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group = nullptr);
-
- /// Return the string
- const std::string& GetString() const { return this->String; }
- const char* GetCString() const { return this->String.c_str(); }
-
-private:
- std::string String;
- unsigned int DataStart;
- bool DoConsume(const std::string& arg, unsigned int index) override;
- void DoReset() override;
-};
-
-/** cmCAEnabler is to be used for options which are off by default and can be
-enabled using a special argument, e.g. EXCLUDE_FROM_ALL in ADD_EXECUTABLE(). */
-class cmCAEnabler : public cmCommandArgument
-{
-public:
- cmCAEnabler(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group = nullptr);
-
- /// Has it been enabled ?
- bool IsEnabled() const { return this->Enabled; }
-
-private:
- bool Enabled;
- bool DoConsume(const std::string& arg, unsigned int index) override;
- void DoReset() override;
-};
-
-/** cmCADisable is to be used for options which are on by default and can be
-disabled using a special argument.*/
-class cmCADisabler : public cmCommandArgument
-{
-public:
- cmCADisabler(cmCommandArgumentsHelper* args, const char* key,
- cmCommandArgumentGroup* group = nullptr);
-
- /// Is it still enabled ?
- bool IsEnabled() const { return this->Enabled; }
-
-private:
- bool Enabled;
- bool DoConsume(const std::string& arg, unsigned int index) override;
- void DoReset() override;
-};
-
-/** Group of arguments, needed for ordering. E.g. WIN32, EXCLUDE_FROM_ALL and
-MACSOX_BUNDLE from ADD_EXECUTABLE() are a group.
-*/
-class cmCommandArgumentGroup
-{
- friend class cmCommandArgument;
-
-public:
- /// All members of this group may follow the given argument
- void Follows(const cmCommandArgument* arg);
-
- /// All members of this group may follow all members of the given group
- void FollowsGroup(const cmCommandArgumentGroup* group);
-
-private:
- std::vector<cmCommandArgument*> ContainedArguments;
-};
-
-class cmCommandArgumentsHelper
-{
-public:
- /// Parse the argument list
- void Parse(const std::vector<std::string>* args,
- std::vector<std::string>* unconsumedArgs);
- /// Add an argument.
- void AddArgument(cmCommandArgument* arg);
-
-private:
- std::vector<cmCommandArgument*> Arguments;
-};
-
-#endif
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index 4717cf6b5..186deb60c 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -9,6 +9,7 @@
#include "cmListFileCache.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
@@ -256,11 +257,7 @@ cmComputeLinkDepends::Compute()
// Iterate in reverse order so we can keep only the last occurrence
// of a shared library.
std::set<int> emmitted;
- for (std::vector<int>::const_reverse_iterator
- li = this->FinalLinkOrder.rbegin(),
- le = this->FinalLinkOrder.rend();
- li != le; ++li) {
- int i = *li;
+ for (int i : cmReverseRange(this->FinalLinkOrder)) {
LinkEntry const& e = this->EntryList[i];
cmGeneratorTarget const* t = e.Target;
// Entries that we know the linker will re-use do not need to be repeated.
@@ -586,11 +583,10 @@ void cmComputeLinkDepends::InferDependencies()
}
// Intersect the sets for this item.
- DependSetList::const_iterator i = sets->begin();
- DependSet common = *i;
- for (++i; i != sets->end(); ++i) {
+ DependSet common = sets->front();
+ for (DependSet const& i : cmMakeRange(*sets).advance(1)) {
DependSet intersection;
- std::set_intersection(common.begin(), common.end(), i->begin(), i->end(),
+ std::set_intersection(common.begin(), common.end(), i.begin(), i.end(),
std::inserter(intersection, intersection.begin()));
common = intersection;
}
@@ -708,9 +704,8 @@ void cmComputeLinkDepends::VisitComponent(unsigned int c)
// Run in reverse order so the topological order will preserve the
// original order where there are no constraints.
EdgeList const& nl = this->CCG->GetComponentGraphEdges(c);
- for (EdgeList::const_reverse_iterator ni = nl.rbegin(); ni != nl.rend();
- ++ni) {
- this->VisitComponent(*ni);
+ for (cmGraphEdge const& edge : cmReverseRange(nl)) {
+ this->VisitComponent(edge);
}
// Assign an ordering id to this component.
diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h
index 252f8748c..dfaaf8b96 100644
--- a/Source/cmComputeLinkDepends.h
+++ b/Source/cmComputeLinkDepends.h
@@ -31,6 +31,9 @@ public:
const std::string& config);
~cmComputeLinkDepends();
+ cmComputeLinkDepends(const cmComputeLinkDepends&) = delete;
+ cmComputeLinkDepends& operator=(const cmComputeLinkDepends&) = delete;
+
// Basic information about each link item.
struct LinkEntry
{
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 3d61665fd..44d8615e0 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -457,8 +457,8 @@ bool cmComputeLinkInformation::Compute()
// We require a link language for the target.
if (this->LinkLanguage.empty()) {
cmSystemTools::Error(
- "CMake can not determine linker language for target: ",
- this->Target->GetName().c_str());
+ "CMake can not determine linker language for target: " +
+ this->Target->GetName());
return false;
}
@@ -1266,7 +1266,7 @@ void cmComputeLinkInformation::AddFrameworkItem(std::string const& item)
void cmComputeLinkInformation::AddDirectoryItem(std::string const& item)
{
if (this->Makefile->IsOn("APPLE") &&
- cmSystemTools::IsPathToFramework(item.c_str())) {
+ cmSystemTools::IsPathToFramework(item)) {
this->AddFrameworkItem(item);
} else {
this->DropDirectoryItem(item);
diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx
index 9b7b02f53..01d4c07e0 100644
--- a/Source/cmComputeTargetDepends.cxx
+++ b/Source/cmComputeTargetDepends.cxx
@@ -11,6 +11,7 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmState.h"
#include "cmStateTypes.h"
@@ -549,10 +550,9 @@ bool cmComputeTargetDepends::ComputeFinalDepends(
int head = -1;
std::set<int> emitted;
NodeList const& nl = components[c];
- for (NodeList::const_reverse_iterator ni = nl.rbegin(); ni != nl.rend();
- ++ni) {
+ for (int ni : cmReverseRange(nl)) {
std::set<int> visited;
- if (!this->IntraComponent(cmap, c, *ni, &head, emitted, visited)) {
+ if (!this->IntraComponent(cmap, c, ni, &head, emitted, visited)) {
// Cycle in add_dependencies within component!
this->ComplainAboutBadComponent(ccg, c, true);
return false;
diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx
index 94ea529ea..e7e91c1a8 100644
--- a/Source/cmConditionEvaluator.cxx
+++ b/Source/cmConditionEvaluator.cxx
@@ -94,10 +94,7 @@ bool cmConditionEvaluator::IsTrue(
}
// store the reduced args in this vector
- cmArgumentList newArgs;
-
- // copy to the list structure
- newArgs.insert(newArgs.end(), args.begin(), args.end());
+ cmArgumentList newArgs(args.begin(), args.end());
// now loop through the arguments and see if we can reduce any of them
// we do this multiple times. Once for each level of precedence
@@ -130,8 +127,8 @@ bool cmConditionEvaluator::IsTrue(
return false;
}
- return this->GetBooleanValueWithAutoDereference(*(newArgs.begin()),
- errorString, status, true);
+ return this->GetBooleanValueWithAutoDereference(newArgs.front(), errorString,
+ status, true);
}
//=========================================================================
@@ -398,7 +395,7 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList& newArgs,
// copy to the list structure
cmArgumentList::iterator argP1 = arg;
argP1++;
- newArgs2.insert(newArgs2.end(), argP1, argClose);
+ cmAppend(newArgs2, argP1, argClose);
newArgs2.pop_back();
// now recursively invoke IsTrue to handle the values inside the
// parenthetical expression
diff --git a/Source/cmConfigureFileCommand.cxx b/Source/cmConfigureFileCommand.cxx
index 8224a0fe3..0917d1102 100644
--- a/Source/cmConfigureFileCommand.cxx
+++ b/Source/cmConfigureFileCommand.cxx
@@ -102,7 +102,7 @@ bool cmConfigureFileCommand::InitialPass(std::vector<std::string> const& args,
int cmConfigureFileCommand::ConfigureFile()
{
- return this->Makefile->ConfigureFile(
- this->InputFile.c_str(), this->OutputFile.c_str(), this->CopyOnly,
- this->AtOnly, this->EscapeQuotes, this->NewLineStyle);
+ return this->Makefile->ConfigureFile(this->InputFile, this->OutputFile,
+ this->CopyOnly, this->AtOnly,
+ this->EscapeQuotes, this->NewLineStyle);
}
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 037d4157a..f12ef0b4a 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -20,6 +20,7 @@
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmVersion.h"
+#include "cm_static_string_view.hxx"
#include "cmake.h"
static std::string const kCMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN =
@@ -42,6 +43,8 @@ static std::string const kCMAKE_LINK_SEARCH_END_STATIC =
"CMAKE_LINK_SEARCH_END_STATIC";
static std::string const kCMAKE_LINK_SEARCH_START_STATIC =
"CMAKE_LINK_SEARCH_START_STATIC";
+static std::string const kCMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT =
+ "CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT";
static std::string const kCMAKE_OSX_ARCHITECTURES = "CMAKE_OSX_ARCHITECTURES";
static std::string const kCMAKE_OSX_DEPLOYMENT_TARGET =
"CMAKE_OSX_DEPLOYMENT_TARGET";
@@ -60,7 +63,8 @@ static std::string const kCMAKE_WARN_DEPRECATED = "CMAKE_WARN_DEPRECATED";
/* GHS Multi platform variables */
static std::set<std::string> ghs_platform_vars{
"GHS_TARGET_PLATFORM", "GHS_PRIMARY_TARGET", "GHS_TOOLSET_ROOT",
- "GHS_OS_ROOT", "GHS_OS_DIR", "GHS_BSP_NAME"
+ "GHS_OS_ROOT", "GHS_OS_DIR", "GHS_BSP_NAME",
+ "GHS_OS_DIR_OPTION"
};
static void writeProperty(FILE* fout, std::string const& targetName,
@@ -118,8 +122,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
}
}
- const char* sourceDirectory = argv[2].c_str();
- const char* projectName = nullptr;
+ 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;
@@ -305,7 +309,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
doing = DoingNone;
} else if (i == 3) {
this->SrcFileSignature = false;
- projectName = argv[i].c_str();
+ projectName = argv[i];
} else if (i == 4 && !this->SrcFileSignature) {
targetName = argv[i];
} else {
@@ -476,7 +480,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
// we need to create a directory and CMakeLists file etc...
// first create the directories
- sourceDirectory = this->BinaryDirectory.c_str();
+ sourceDirectory = this->BinaryDirectory;
// now create a CMakeLists.txt file in that directory
FILE* fout = cmsys::SystemTools::Fopen(outFileName, "w");
@@ -499,6 +503,13 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
fprintf(fout, "set(CMAKE_MODULE_PATH \"%s\")\n", def);
}
+ /* Set MSVC runtime library policy to match our selection. */
+ if (const char* msvcRuntimeLibraryDefault =
+ this->Makefile->GetDefinition(kCMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)) {
+ fprintf(fout, "cmake_policy(SET CMP0091 %s)\n",
+ *msvcRuntimeLibraryDefault ? "NEW" : "OLD");
+ }
+
std::string projectLangs;
for (std::string const& li : testLangs) {
projectLangs += " " + li;
@@ -659,6 +670,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
vars.insert(kCMAKE_SYSROOT_COMPILE);
vars.insert(kCMAKE_SYSROOT_LINK);
vars.insert(kCMAKE_WARN_DEPRECATED);
+ vars.emplace("CMAKE_MSVC_RUNTIME_LIBRARY"_s);
if (const char* varListStr = this->Makefile->GetDefinition(
kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) {
@@ -896,7 +908,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
// Forward the GHS variables to the inner project cache.
for (std::string const& var : ghs_platform_vars) {
if (const char* val = this->Makefile->GetDefinition(var)) {
- std::string flag = "-D" + var + "=" + val;
+ std::string flag = "-D" + var + "=" + "'" + val + "'";
cmakeFlags.push_back(std::move(flag));
}
}
@@ -938,7 +950,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
<< " '" << copyFile << "'\n";
/* clang-format on */
if (!this->FindErrorMessage.empty()) {
- emsg << this->FindErrorMessage.c_str();
+ emsg << this->FindErrorMessage;
}
if (copyFileError.empty()) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, emsg.str());
@@ -965,8 +977,8 @@ void cmCoreTryCompile::CleanupFiles(std::string const& binDir)
if (binDir.find("CMakeTmp") == std::string::npos) {
cmSystemTools::Error(
"TRY_COMPILE attempt to remove -rf directory that does not contain "
- "CMakeTmp:",
- binDir.c_str());
+ "CMakeTmp:" +
+ binDir);
return;
}
diff --git a/Source/cmCreateTestSourceList.cxx b/Source/cmCreateTestSourceList.cxx
index 69532e61b..b78493f99 100644
--- a/Source/cmCreateTestSourceList.cxx
+++ b/Source/cmCreateTestSourceList.cxx
@@ -136,8 +136,7 @@ bool cmCreateTestSourceList::InitialPass(std::vector<std::string> const& args,
this->Makefile->AddDefinition("CMAKE_FUNCTION_TABLE_ENTIRES",
functionMapCode.c_str());
bool res = true;
- if (!this->Makefile->ConfigureFile(configFile.c_str(), driver.c_str(), false,
- true, false)) {
+ if (!this->Makefile->ConfigureFile(configFile, driver, false, true, false)) {
res = false;
}
diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx
index 242ceaab4..7402eeb37 100644
--- a/Source/cmCustomCommand.cxx
+++ b/Source/cmCustomCommand.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCustomCommand.h"
+#include "cmAlgorithms.h"
#include "cmMakefile.h"
#include <utility>
@@ -54,13 +55,12 @@ const char* cmCustomCommand::GetComment() const
void cmCustomCommand::AppendCommands(const cmCustomCommandLines& commandLines)
{
- this->CommandLines.insert(this->CommandLines.end(), commandLines.begin(),
- commandLines.end());
+ cmAppend(this->CommandLines, commandLines);
}
void cmCustomCommand::AppendDepends(const std::vector<std::string>& depends)
{
- this->Depends.insert(this->Depends.end(), depends.begin(), depends.end());
+ cmAppend(this->Depends, depends);
}
bool cmCustomCommand::GetEscapeOldStyle() const
@@ -101,8 +101,7 @@ void cmCustomCommand::SetImplicitDepends(ImplicitDependsList const& l)
void cmCustomCommand::AppendImplicitDepends(ImplicitDependsList const& l)
{
- this->ImplicitDepends.insert(this->ImplicitDepends.end(), l.begin(),
- l.end());
+ cmAppend(this->ImplicitDepends, l);
}
bool cmCustomCommand::GetUsesTerminal() const
@@ -134,3 +133,13 @@ void cmCustomCommand::SetDepfile(const std::string& depfile)
{
this->Depfile = depfile;
}
+
+const std::string& cmCustomCommand::GetJobPool() const
+{
+ return this->JobPool;
+}
+
+void cmCustomCommand::SetJobPool(const std::string& job_pool)
+{
+ this->JobPool = job_pool;
+}
diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h
index 50f15a46f..9a6f2390c 100644
--- a/Source/cmCustomCommand.h
+++ b/Source/cmCustomCommand.h
@@ -89,6 +89,10 @@ public:
const std::string& GetDepfile() const;
void SetDepfile(const std::string& depfile);
+ /** Set/Get the job_pool (used by the Ninja generator) */
+ const std::string& GetJobPool() const;
+ void SetJobPool(const std::string& job_pool);
+
private:
std::vector<std::string> Outputs;
std::vector<std::string> Byproducts;
@@ -99,6 +103,7 @@ private:
std::string Comment;
std::string WorkingDirectory;
std::string Depfile;
+ std::string JobPool;
bool HaveComment = false;
bool EscapeAllowMakeVars = false;
bool EscapeOldStyle = true;
diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
index 6bf99468e..89aaad0dc 100644
--- a/Source/cmCustomCommandGenerator.cxx
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCustomCommandGenerator.h"
+#include "cmAlgorithms.h"
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
#include "cmGeneratorExpression.h"
@@ -33,9 +34,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
this->GE->Parse(clarg);
std::string parsed_arg = cge->Evaluate(this->LG, this->Config);
if (this->CC.GetCommandExpandLists()) {
- std::vector<std::string> ExpandedArg;
- cmSystemTools::ExpandListArgument(parsed_arg, ExpandedArg);
- argv.insert(argv.end(), ExpandedArg.begin(), ExpandedArg.end());
+ cmAppend(argv, cmSystemTools::ExpandedListArgument(parsed_arg));
} else {
argv.push_back(std::move(parsed_arg));
}
@@ -54,15 +53,14 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
std::vector<std::string> depends = this->CC.GetDepends();
for (std::string const& d : depends) {
std::unique_ptr<cmCompiledGeneratorExpression> cge = this->GE->Parse(d);
- std::vector<std::string> result;
- cmSystemTools::ExpandListArgument(cge->Evaluate(this->LG, this->Config),
- result);
+ std::vector<std::string> result = cmSystemTools::ExpandedListArgument(
+ cge->Evaluate(this->LG, this->Config));
for (std::string& it : result) {
if (cmSystemTools::FileIsFullPath(it)) {
it = cmSystemTools::CollapseFullPath(it);
}
}
- this->Depends.insert(this->Depends.end(), result.begin(), result.end());
+ cmAppend(this->Depends, result);
}
const std::string& workingdirectory = this->CC.GetWorkingDirectory();
@@ -77,6 +75,8 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
cmSystemTools::CollapseFullPath(this->WorkingDirectory, build_dir);
}
}
+
+ this->FillEmulatorsWithArguments();
}
cmCustomCommandGenerator::~cmCustomCommandGenerator()
@@ -89,19 +89,38 @@ unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const
return static_cast<unsigned int>(this->CC.GetCommandLines().size());
}
-const char* cmCustomCommandGenerator::GetCrossCompilingEmulator(
- unsigned int c) const
+void cmCustomCommandGenerator::FillEmulatorsWithArguments()
{
if (!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING")) {
- return nullptr;
+ return;
}
- std::string const& argv0 = this->CommandLines[c][0];
- cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
- if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
- !target->IsImported()) {
- return target->GetProperty("CROSSCOMPILING_EMULATOR");
+
+ for (unsigned int c = 0; c < this->GetNumberOfCommands(); ++c) {
+ std::string const& argv0 = this->CommandLines[c][0];
+ cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
+ if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
+ !target->IsImported()) {
+
+ const char* emulator_property =
+ target->GetProperty("CROSSCOMPILING_EMULATOR");
+ if (!emulator_property) {
+ continue;
+ }
+
+ this->EmulatorsWithArguments.emplace_back();
+ cmSystemTools::ExpandListArgument(emulator_property,
+ this->EmulatorsWithArguments[c]);
+ }
}
- return nullptr;
+}
+
+std::vector<std::string> cmCustomCommandGenerator::GetCrossCompilingEmulator(
+ unsigned int c) const
+{
+ if (c >= this->EmulatorsWithArguments.size()) {
+ return std::vector<std::string>();
+ }
+ return this->EmulatorsWithArguments[c];
}
const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const
@@ -131,8 +150,9 @@ bool cmCustomCommandGenerator::HasOnlyEmptyCommandLines() const
std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
{
- if (const char* emulator = this->GetCrossCompilingEmulator(c)) {
- return std::string(emulator);
+ std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c);
+ if (!emulator.empty()) {
+ return emulator[0];
}
if (const char* location = this->GetArgv0Location(c)) {
return std::string(location);
@@ -170,9 +190,20 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c,
std::string& cmd) const
{
unsigned int offset = 1;
- if (this->GetCrossCompilingEmulator(c) != nullptr) {
+ std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c);
+ if (!emulator.empty()) {
+ for (unsigned j = 1; j < emulator.size(); ++j) {
+ cmd += " ";
+ if (this->OldStyle) {
+ cmd += escapeForShellOldStyle(emulator[j]);
+ } else {
+ cmd += this->LG->EscapeForShell(emulator[j], this->MakeVars);
+ }
+ }
+
offset = 0;
}
+
cmCustomCommandLine const& commandLine = this->CommandLines[c];
for (unsigned int j = offset; j < commandLine.size(); ++j) {
std::string arg;
diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h
index 9684cffa8..766f4b81d 100644
--- a/Source/cmCustomCommandGenerator.h
+++ b/Source/cmCustomCommandGenerator.h
@@ -22,16 +22,21 @@ class cmCustomCommandGenerator
bool MakeVars;
cmGeneratorExpression* GE;
cmCustomCommandLines CommandLines;
+ std::vector<std::vector<std::string>> EmulatorsWithArguments;
std::vector<std::string> Depends;
std::string WorkingDirectory;
- const char* GetCrossCompilingEmulator(unsigned int c) const;
+ void FillEmulatorsWithArguments();
+ std::vector<std::string> GetCrossCompilingEmulator(unsigned int c) const;
const char* GetArgv0Location(unsigned int c) const;
public:
cmCustomCommandGenerator(cmCustomCommand const& cc, std::string config,
cmLocalGenerator* lg);
~cmCustomCommandGenerator();
+ cmCustomCommandGenerator(const cmCustomCommandGenerator&) = delete;
+ cmCustomCommandGenerator& operator=(const cmCustomCommandGenerator&) =
+ delete;
cmCustomCommand const& GetCC() const { return this->CC; }
unsigned int GetNumberOfCommands() const;
std::string GetCommand(unsigned int c) const;
diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx
index 7d1d31624..ed76dbf47 100644
--- a/Source/cmDepends.cxx
+++ b/Source/cmDepends.cxx
@@ -2,7 +2,8 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmDepends.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTime.h"
+#include "cmFileTimeCache.h"
#include "cmGeneratedFileStream.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
@@ -10,46 +11,39 @@
#include "cmsys/FStream.hxx"
#include <sstream>
-#include <string.h>
#include <utility>
cmDepends::cmDepends(cmLocalGenerator* lg, std::string targetDir)
: LocalGenerator(lg)
, TargetDirectory(std::move(targetDir))
- , Dependee(new char[MaxPath])
- , Depender(new char[MaxPath])
{
}
-cmDepends::~cmDepends()
-{
- delete[] this->Dependee;
- delete[] this->Depender;
-}
+cmDepends::~cmDepends() = default;
bool cmDepends::Write(std::ostream& makeDepends, std::ostream& internalDepends)
{
- // Lookup the set of sources to scan.
- std::string srcLang = "CMAKE_DEPENDS_CHECK_";
- srcLang += this->Language;
- cmMakefile* mf = this->LocalGenerator->GetMakefile();
- std::string const& srcStr = mf->GetSafeDefinition(srcLang);
- std::vector<std::string> pairs;
- cmSystemTools::ExpandListArgument(srcStr, pairs);
-
std::map<std::string, std::set<std::string>> dependencies;
- for (std::vector<std::string>::iterator si = pairs.begin();
- si != pairs.end();) {
- // Get the source and object file.
- std::string const& src = *si++;
- if (si == pairs.end()) {
- break;
+ {
+ // Lookup the set of sources to scan.
+ std::vector<std::string> pairs;
+ {
+ std::string const srcLang = "CMAKE_DEPENDS_CHECK_" + this->Language;
+ cmMakefile* mf = this->LocalGenerator->GetMakefile();
+ cmSystemTools::ExpandListArgument(mf->GetSafeDefinition(srcLang), pairs);
+ }
+ for (std::vector<std::string>::iterator si = pairs.begin();
+ si != pairs.end();) {
+ // Get the source and object file.
+ std::string const& src = *si++;
+ if (si == pairs.end()) {
+ break;
+ }
+ std::string const& obj = *si++;
+ dependencies[obj].insert(src);
}
- std::string const& obj = *si++;
- dependencies[obj].insert(src);
}
for (auto const& d : dependencies) {
-
// Write the dependencies for this pair.
if (!this->WriteDependencies(d.second, d.first, makeDepends,
internalDepends)) {
@@ -67,7 +61,7 @@ bool cmDepends::Finalize(std::ostream& /*unused*/, std::ostream& /*unused*/)
bool cmDepends::Check(const std::string& makeFile,
const std::string& internalFile,
- std::map<std::string, DependencyVector>& validDeps)
+ DependencyMap& validDeps)
{
// Check whether dependencies must be regenerated.
bool okay = true;
@@ -76,9 +70,9 @@ bool cmDepends::Check(const std::string& makeFile,
// Clear all dependencies so they will be regenerated.
this->Clear(makeFile);
cmSystemTools::RemoveFile(internalFile);
+ this->FileTimeCache->Remove(internalFile);
okay = false;
}
-
return okay;
}
@@ -107,48 +101,62 @@ bool cmDepends::WriteDependencies(const std::set<std::string>& /*unused*/,
return false;
}
-bool cmDepends::CheckDependencies(
- std::istream& internalDepends, const std::string& internalDependsFileName,
- std::map<std::string, DependencyVector>& validDeps)
+bool cmDepends::CheckDependencies(std::istream& internalDepends,
+ const std::string& internalDependsFileName,
+ DependencyMap& validDeps)
{
+ // Read internal depends file time
+ cmFileTime internalDependsTime;
+ if (!this->FileTimeCache->Load(internalDependsFileName,
+ internalDependsTime)) {
+ return false;
+ }
+
// Parse dependencies from the stream. If any dependee is missing
// or newer than the depender then dependencies should be
// regenerated.
bool okay = true;
bool dependerExists = false;
- DependencyVector* currentDependencies = nullptr;
- while (internalDepends.getline(this->Dependee, this->MaxPath)) {
- if (this->Dependee[0] == 0 || this->Dependee[0] == '#' ||
- this->Dependee[0] == '\r') {
+ std::string line;
+ line.reserve(1024);
+ std::string depender;
+ std::string dependee;
+ cmFileTime dependerTime;
+ cmFileTime dependeeTime;
+ std::vector<std::string>* currentDependencies = nullptr;
+
+ while (std::getline(internalDepends, line)) {
+ // Check if this an empty or a comment line
+ if (line.empty() || line.front() == '#') {
continue;
}
- size_t len = internalDepends.gcount() - 1;
- if (this->Dependee[len - 1] == '\r') {
- len--;
- this->Dependee[len] = 0;
+ // Drop carriage return character at the end
+ if (line.back() == '\r') {
+ line.pop_back();
+ if (line.empty()) {
+ continue;
+ }
}
- if (this->Dependee[0] != ' ') {
- memcpy(this->Depender, this->Dependee, len + 1);
- // Calling FileExists() for the depender here saves in many cases 50%
- // of the calls to FileExists() further down in the loop. E.g. for
- // kdelibs/khtml this reduces the number of calls from 184k down to 92k,
- // or the time for cmake -E cmake_depends from 0.3 s down to 0.21 s.
- dependerExists = cmSystemTools::FileExists(this->Depender);
+ // Check if this a depender line
+ if (line.front() != ' ') {
+ depender = line;
+ dependerExists = this->FileTimeCache->Load(depender, dependerTime);
// If we erase validDeps[this->Depender] by overwriting it with an empty
// vector, we lose dependencies for dependers that have multiple
// entries. No need to initialize the entry, std::map will do so on first
// access.
- currentDependencies = &validDeps[this->Depender];
+ currentDependencies = &validDeps[depender];
continue;
}
- /*
- // Parse the dependency line.
- if(!this->ParseDependency(line.c_str()))
- {
- continue;
- }
- */
+
+ // This is a dependee line
+ dependee = line.substr(1);
+
+ // Add dependee to depender's list
+ if (currentDependencies != nullptr) {
+ currentDependencies->push_back(dependee);
+ }
// Dependencies must be regenerated
// * if the dependee does not exist
@@ -156,13 +164,8 @@ bool cmDepends::CheckDependencies(
// * if the depender does not exist, but the dependee is newer than the
// depends file
bool regenerate = false;
- const std::string dependee(this->Dependee + 1);
- const std::string depender(this->Depender);
- if (currentDependencies != nullptr) {
- currentDependencies->push_back(dependee);
- }
-
- if (!cmSystemTools::FileExists(dependee)) {
+ bool dependeeExists = this->FileTimeCache->Load(dependee, dependeeTime);
+ if (!dependeeExists) {
// The dependee does not exist.
regenerate = true;
@@ -173,45 +176,38 @@ bool cmDepends::CheckDependencies(
<< depender << "\"." << std::endl;
cmSystemTools::Stdout(msg.str());
}
- } else {
- if (dependerExists) {
- // The dependee and depender both exist. Compare file times.
- int result = 0;
- if ((!this->FileComparison->FileTimeCompare(depender, dependee,
- &result) ||
- result < 0)) {
- // The depender is older than the dependee.
- regenerate = true;
-
- // Print verbose output.
- if (this->Verbose) {
- std::ostringstream msg;
- msg << "Dependee \"" << dependee << "\" is newer than depender \""
- << depender << "\"." << std::endl;
- cmSystemTools::Stdout(msg.str());
- }
+ } else if (dependerExists) {
+ // The dependee and depender both exist. Compare file times.
+ if (dependerTime.Older(dependeeTime)) {
+ // The depender is older than the dependee.
+ regenerate = true;
+
+ // Print verbose output.
+ if (this->Verbose) {
+ std::ostringstream msg;
+ msg << "Dependee \"" << dependee << "\" is newer than depender \""
+ << depender << "\"." << std::endl;
+ cmSystemTools::Stdout(msg.str());
}
- } else {
- // The dependee exists, but the depender doesn't. Regenerate if the
- // internalDepends file is older than the dependee.
- int result = 0;
- if ((!this->FileComparison->FileTimeCompare(internalDependsFileName,
- dependee, &result) ||
- result < 0)) {
- // The depends-file is older than the dependee.
- regenerate = true;
-
- // Print verbose output.
- if (this->Verbose) {
- std::ostringstream msg;
- msg << "Dependee \"" << dependee
- << "\" is newer than depends file \""
- << internalDependsFileName << "\"." << std::endl;
- cmSystemTools::Stdout(msg.str());
- }
+ }
+ } else {
+ // The dependee exists, but the depender doesn't. Regenerate if the
+ // internalDepends file is older than the dependee.
+ if (internalDependsTime.Older(dependeeTime)) {
+ // The depends-file is older than the dependee.
+ regenerate = true;
+
+ // Print verbose output.
+ if (this->Verbose) {
+ std::ostringstream msg;
+ msg << "Dependee \"" << dependee
+ << "\" is newer than depends file \"" << internalDependsFileName
+ << "\"." << std::endl;
+ cmSystemTools::Stdout(msg.str());
}
}
}
+
if (regenerate) {
// Dependencies must be regenerated.
okay = false;
@@ -219,13 +215,14 @@ bool cmDepends::CheckDependencies(
// Remove the information of this depender from the map, it needs
// to be rescanned
if (currentDependencies != nullptr) {
- validDeps.erase(this->Depender);
+ validDeps.erase(depender);
currentDependencies = nullptr;
}
// Remove the depender to be sure it is rebuilt.
if (dependerExists) {
cmSystemTools::RemoveFile(depender);
+ this->FileTimeCache->Remove(depender);
dependerExists = false;
}
}
diff --git a/Source/cmDepends.h b/Source/cmDepends.h
index 20c91ca57..b7475f0ae 100644
--- a/Source/cmDepends.h
+++ b/Source/cmDepends.h
@@ -8,11 +8,10 @@
#include <iosfwd>
#include <map>
#include <set>
-#include <stddef.h>
#include <string>
#include <vector>
-class cmFileTimeComparison;
+class cmFileTimeCache;
class cmLocalGenerator;
/** \class cmDepends
@@ -25,6 +24,9 @@ class cmLocalGenerator;
class cmDepends
{
public:
+ typedef std::map<std::string, std::vector<std::string>> DependencyMap;
+
+public:
/** Instances need to know the build directory name and the relative
path from the build directory to the target file. */
cmDepends(cmLocalGenerator* lg = nullptr, std::string targetDir = "");
@@ -56,26 +58,19 @@ public:
/** Write dependencies for the target file. */
bool Write(std::ostream& makeDepends, std::ostream& internalDepends);
- class DependencyVector : public std::vector<std::string>
- {
- };
-
/** Check dependencies for the target file. Returns true if
dependencies are okay and false if they must be generated. If
they must be generated Clear has already been called to wipe out
the old dependencies.
Dependencies which are still valid will be stored in validDeps. */
bool Check(const std::string& makeFile, const std::string& internalFile,
- std::map<std::string, DependencyVector>& validDeps);
+ DependencyMap& validDeps);
/** Clear dependencies for the target file so they will be regenerated. */
void Clear(const std::string& file);
/** Set the file comparison object */
- void SetFileComparison(cmFileTimeComparison* fc)
- {
- this->FileComparison = fc;
- }
+ void SetFileTimeCache(cmFileTimeCache* fc) { this->FileTimeCache = fc; }
protected:
// Write dependencies for the target file to the given stream.
@@ -88,9 +83,9 @@ protected:
// Check dependencies for the target file in the given stream.
// Return false if dependencies must be regenerated and true
// otherwise.
- virtual bool CheckDependencies(
- std::istream& internalDepends, const std::string& internalDependsFileName,
- std::map<std::string, DependencyVector>& validDeps);
+ virtual bool CheckDependencies(std::istream& internalDepends,
+ const std::string& internalDependsFileName,
+ DependencyMap& validDeps);
// Finalize the dependency information for the target.
virtual bool Finalize(std::ostream& makeDepends,
@@ -101,17 +96,13 @@ protected:
// Flag for verbose output.
bool Verbose = false;
- cmFileTimeComparison* FileComparison = nullptr;
+ cmFileTimeCache* FileTimeCache = nullptr;
std::string Language;
// The full path to the target's build directory.
std::string TargetDirectory;
- size_t MaxPath = 16384;
- char* Dependee;
- char* Depender;
-
// The include file search path.
std::vector<std::string> IncludePath;
diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx
index b1630f9ae..dc49c18f8 100644
--- a/Source/cmDependsC.cxx
+++ b/Source/cmDependsC.cxx
@@ -6,7 +6,7 @@
#include <utility>
#include "cmAlgorithms.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTime.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
@@ -21,9 +21,8 @@
cmDependsC::cmDependsC() = default;
-cmDependsC::cmDependsC(
- cmLocalGenerator* lg, const std::string& targetDir, const std::string& lang,
- const std::map<std::string, DependencyVector>* validDeps)
+cmDependsC::cmDependsC(cmLocalGenerator* lg, const std::string& targetDir,
+ const std::string& lang, const DependencyMap* validDeps)
: cmDepends(lg, targetDir)
, ValidDeps(validDeps)
{
@@ -102,8 +101,7 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
this->LocalGenerator->MaybeConvertToRelativePath(binDir, obj);
if (this->ValidDeps != nullptr) {
- std::map<std::string, DependencyVector>::const_iterator tmpIt =
- this->ValidDeps->find(obj_i);
+ auto const tmpIt = this->ValidDeps->find(obj_i);
if (tmpIt != this->ValidDeps->end()) {
dependencies.insert(tmpIt->second.begin(), tmpIt->second.end());
haveDeps = true;
@@ -123,12 +121,6 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
}
std::set<std::string> scanned;
-
- // Use reserve to allocate enough memory for tempPathStr
- // so that during the loops no memory is allocated or freed
- std::string tempPathStr;
- tempPathStr.reserve(4 * 1024);
-
while (!this->Unscanned.empty()) {
// Get the next file to scan.
UnscannedEntry current = this->Unscanned.front();
@@ -147,22 +139,21 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
// the source containing the include statement.
fullName = current.QuotedLocation;
} else {
- std::map<std::string, std::string>::iterator headerLocationIt =
+ auto headerLocationIt =
this->HeaderLocationCache.find(current.FileName);
if (headerLocationIt != this->HeaderLocationCache.end()) {
fullName = headerLocationIt->second;
} else {
- for (std::string const& i : this->IncludePath) {
+ for (std::string const& iPath : this->IncludePath) {
// Construct the name of the file as if it were in the current
// include directory. Avoid using a leading "./".
-
- tempPathStr =
- cmSystemTools::CollapseCombinedPath(i, current.FileName);
+ std::string tmpPath =
+ cmSystemTools::CollapseFullPath(current.FileName, iPath);
// Look for the file in this location.
- if (cmSystemTools::FileExists(tempPathStr, true)) {
- fullName = tempPathStr;
- HeaderLocationCache[current.FileName] = fullName;
+ if (cmSystemTools::FileExists(tmpPath, true)) {
+ fullName = tmpPath;
+ this->HeaderLocationCache[current.FileName] = std::move(tmpPath);
break;
}
}
@@ -173,8 +164,7 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
// regex.
if (fullName.empty() &&
this->IncludeRegexComplain.find(current.FileName)) {
- cmSystemTools::Error("Cannot find file \"", current.FileName.c_str(),
- "\".");
+ cmSystemTools::Error("Cannot find file \"" + current.FileName + "\".");
return false;
}
@@ -184,8 +174,7 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
scanned.insert(fullName);
// Check whether this file is already in the cache
- std::map<std::string, cmIncludeLines*>::iterator fileIt =
- this->FileCache.find(fullName);
+ auto fileIt = this->FileCache.find(fullName);
if (fileIt != this->FileCache.end()) {
fileIt->second->Used = true;
dependencies.insert(fullName);
@@ -257,6 +246,8 @@ void cmDependsC::ReadCacheFile()
cmIncludeLines* cacheEntry = nullptr;
bool haveFileName = false;
+ cmFileTime cacheFileTime;
+ bool const cacheFileTimeGood = cacheFileTime.Load(this->CacheFileName);
while (cmSystemTools::GetLineFromStream(fin, line)) {
if (line.empty()) {
cacheEntry = nullptr;
@@ -266,11 +257,12 @@ void cmDependsC::ReadCacheFile()
// the first line after an empty line is the name of the parsed file
if (!haveFileName) {
haveFileName = true;
- int newer = 0;
- cmFileTimeComparison comp;
- bool res = comp.FileTimeCompare(this->CacheFileName, line, &newer);
- if (res && newer == 1) // cache is newer than the parsed file
+ cmFileTime fileTime;
+ bool const res = cacheFileTimeGood && fileTime.Load(line);
+ bool const newer = res && cacheFileTime.Newer(fileTime);
+
+ if (res && newer) // cache is newer than the parsed file
{
cacheEntry = new cmIncludeLines;
this->FileCache[line] = cacheEntry;
@@ -368,7 +360,7 @@ void cmDependsC::Scan(std::istream& is, const std::string& directory,
// must check for the file in the directory containing the
// file we are scanning.
entry.QuotedLocation =
- cmSystemTools::CollapseCombinedPath(directory, entry.FileName);
+ cmSystemTools::CollapseFullPath(entry.FileName, directory);
}
// Queue the file if it has not yet been encountered and it
diff --git a/Source/cmDependsC.h b/Source/cmDependsC.h
index eee5ae15c..3fc839e43 100644
--- a/Source/cmDependsC.h
+++ b/Source/cmDependsC.h
@@ -27,8 +27,7 @@ public:
relative path from the build directory to the target file. */
cmDependsC();
cmDependsC(cmLocalGenerator* lg, const std::string& targetDir,
- const std::string& lang,
- const std::map<std::string, DependencyVector>* validDeps);
+ const std::string& lang, const DependencyMap* validDeps);
/** Virtual destructor to cleanup subclasses properly. */
~cmDependsC() override;
@@ -81,7 +80,7 @@ public:
};
protected:
- const std::map<std::string, DependencyVector>* ValidDeps = nullptr;
+ const DependencyMap* ValidDeps = nullptr;
std::set<std::string> Encountered;
std::queue<UnscannedEntry> Unscanned;
diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx
index 3f036a9de..178e18b5f 100644
--- a/Source/cmDependsFortran.cxx
+++ b/Source/cmDependsFortran.cxx
@@ -295,7 +295,7 @@ void cmDependsFortran::MatchRemoteModules(std::istream& fin,
// They do not include the ".mod" extension.
mod += ".mod";
}
- this->ConsiderModule(mod.c_str() + 1, stampDir);
+ this->ConsiderModule(mod.substr(1), stampDir);
}
} else if (line == "provides") {
doing_provides = true;
diff --git a/Source/cmDependsJava.cxx b/Source/cmDependsJava.cxx
index 2485e15fd..b17b2ba74 100644
--- a/Source/cmDependsJava.cxx
+++ b/Source/cmDependsJava.cxx
@@ -24,8 +24,7 @@ bool cmDependsJava::WriteDependencies(const std::set<std::string>& sources,
bool cmDependsJava::CheckDependencies(
std::istream& /*internalDepends*/,
- const std::string& /*internalDependsFileName*/,
- std::map<std::string, DependencyVector>& /*validDeps*/)
+ const std::string& /*internalDependsFileName*/, DependencyMap& /*validDeps*/)
{
return true;
}
diff --git a/Source/cmDependsJava.h b/Source/cmDependsJava.h
index 109ef13d1..dd671a1b6 100644
--- a/Source/cmDependsJava.h
+++ b/Source/cmDependsJava.h
@@ -8,7 +8,6 @@
#include "cmDepends.h"
#include <iosfwd>
-#include <map>
#include <set>
#include <string>
@@ -33,9 +32,9 @@ protected:
bool WriteDependencies(const std::set<std::string>& sources,
const std::string& file, std::ostream& makeDepends,
std::ostream& internalDepends) override;
- bool CheckDependencies(
- std::istream& internalDepends, const std::string& internalDependsFileName,
- std::map<std::string, DependencyVector>& validDeps) override;
+ bool CheckDependencies(std::istream& internalDepends,
+ const std::string& internalDependsFileName,
+ DependencyMap& validDeps) override;
};
#endif
diff --git a/Source/cmDependsJavaParserHelper.cxx b/Source/cmDependsJavaParserHelper.cxx
index 792db48a4..12d875d6f 100644
--- a/Source/cmDependsJavaParserHelper.cxx
+++ b/Source/cmDependsJavaParserHelper.cxx
@@ -5,6 +5,7 @@
#include "cmDependsJavaLexer.h"
#include "cmSystemTools.h"
+#include "cm_string_view.hxx"
#include "cmsys/FStream.hxx"
#include <iostream>
#include <stdio.h>
@@ -298,14 +299,10 @@ void cmDependsJavaParserHelper::Error(const char* str)
unsigned long pos = static_cast<unsigned long>(this->InputBufferPos);
fprintf(stderr, "JPError: %s (%lu / Line: %d)\n", str, pos,
this->CurrentLine);
- int cc;
- std::cerr << "String: [";
- for (cc = 0;
- cc < 30 && *(this->InputBuffer.c_str() + this->InputBufferPos + cc);
- cc++) {
- std::cerr << *(this->InputBuffer.c_str() + this->InputBufferPos + cc);
- }
- std::cerr << "]" << std::endl;
+ std::cerr << "String: ["
+ << cm::string_view{ this->InputBuffer }.substr(
+ this->InputBufferPos, 30)
+ << "]" << std::endl;
}
void cmDependsJavaParserHelper::UpdateCombine(const char* str1,
diff --git a/Source/cmDependsJavaParserHelper.h b/Source/cmDependsJavaParserHelper.h
index 0b445d924..a673b5bbb 100644
--- a/Source/cmDependsJavaParserHelper.h
+++ b/Source/cmDependsJavaParserHelper.h
@@ -24,6 +24,10 @@ public:
cmDependsJavaParserHelper();
~cmDependsJavaParserHelper();
+ cmDependsJavaParserHelper(const cmDependsJavaParserHelper&) = delete;
+ cmDependsJavaParserHelper& operator=(const cmDependsJavaParserHelper&) =
+ delete;
+
int ParseString(const char* str, int verb);
int ParseFile(const char* file);
diff --git a/Source/cmDocumentationSection.h b/Source/cmDocumentationSection.h
index 7031b525d..19c7407b7 100644
--- a/Source/cmDocumentationSection.h
+++ b/Source/cmDocumentationSection.h
@@ -5,6 +5,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cmAlgorithms.h"
#include "cmDocumentationEntry.h"
#include <string>
@@ -46,7 +47,7 @@ public:
}
void Append(const std::vector<cmDocumentationEntry>& entries)
{
- this->Entries.insert(this->Entries.end(), entries.begin(), entries.end());
+ cmAppend(this->Entries, entries);
}
/** Append an entry to this section using NULL terminated chars */
diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx
index 27f91317f..222646365 100644
--- a/Source/cmELF.cxx
+++ b/Source/cmELF.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmELF.h"
+#include "cmAlgorithms.h"
#include "cm_kwiml.h"
#include "cmsys/FStream.hxx"
#include <map>
@@ -572,7 +573,7 @@ std::vector<char> cmELFInternalImpl<Types>::EncodeDynamicEntries(
}
char* pdyn = reinterpret_cast<char*>(&dyn);
- result.insert(result.end(), pdyn, pdyn + sizeof(ELF_Dyn));
+ cmAppend(result, pdyn, pdyn + sizeof(ELF_Dyn));
}
return result;
diff --git a/Source/cmELF.h b/Source/cmELF.h
index c8a91e4ea..987f0c3a4 100644
--- a/Source/cmELF.h
+++ b/Source/cmELF.h
@@ -28,6 +28,9 @@ public:
/** Destruct. */
~cmELF();
+ cmELF(const cmELF&) = delete;
+ cmELF& operator=(const cmELF&) = delete;
+
/** Get the error message if any. */
std::string const& GetErrorMessage() const { return this->ErrorMessage; }
diff --git a/Source/cmExecProgramCommand.cxx b/Source/cmExecProgramCommand.cxx
index 75a7786a4..4b559e71a 100644
--- a/Source/cmExecProgramCommand.cxx
+++ b/Source/cmExecProgramCommand.cxx
@@ -67,7 +67,7 @@ bool cmExecProgramCommand::InitialPass(std::vector<std::string> const& args,
std::string command;
if (!arguments.empty()) {
- command = cmSystemTools::ConvertToRunCommandPath(args[0].c_str());
+ command = cmSystemTools::ConvertToRunCommandPath(args[0]);
command += " ";
command += arguments;
} else {
@@ -82,11 +82,11 @@ bool cmExecProgramCommand::InitialPass(std::vector<std::string> const& args,
bool result = true;
if (args.size() - count == 2) {
cmSystemTools::MakeDirectory(args[1]);
- result = cmExecProgramCommand::RunCommand(command.c_str(), output, retVal,
+ result = cmExecProgramCommand::RunCommand(command, output, retVal,
args[1].c_str(), verbose);
} else {
- result = cmExecProgramCommand::RunCommand(command.c_str(), output, retVal,
- nullptr, verbose);
+ result = cmExecProgramCommand::RunCommand(command, output, retVal, nullptr,
+ verbose);
}
if (!result) {
retVal = -1;
@@ -115,7 +115,7 @@ bool cmExecProgramCommand::InitialPass(std::vector<std::string> const& args,
return true;
}
-bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
+bool cmExecProgramCommand::RunCommand(std::string command, std::string& output,
int& retVal, const char* dir,
bool verbose, Encoding encoding)
{
@@ -128,12 +128,11 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
// try to find the program, and if the program can not be
// found use system to run the command as it must be a built in
// shell command like echo or dir
- int count = 0;
- std::string shortCmd;
- if (command[0] == '\"') {
+ if (!command.empty() && command[0] == '\"') {
// count the number of quotes
- for (const char* s = command; *s != 0; ++s) {
- if (*s == '\"') {
+ int count = 0;
+ for (char c : command) {
+ if (c == '\"') {
count++;
if (count > 2) {
break;
@@ -147,20 +146,21 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
if (count > 2) {
cmsys::RegularExpression quoted("^\"([^\"]*)\"[ \t](.*)");
if (quoted.find(command)) {
+ std::string shortCmd;
std::string cmd = quoted.match(1);
std::string args = quoted.match(2);
if (!cmSystemTools::FileExists(cmd)) {
shortCmd = cmd;
- } else if (!cmSystemTools::GetShortPath(cmd.c_str(), shortCmd)) {
- cmSystemTools::Error("GetShortPath failed for ", cmd.c_str());
+ } else if (!cmSystemTools::GetShortPath(cmd, shortCmd)) {
+ cmSystemTools::Error("GetShortPath failed for " + cmd);
return false;
}
shortCmd += " ";
shortCmd += args;
- command = shortCmd.c_str();
+ command = shortCmd;
} else {
- cmSystemTools::Error("Could not parse command line with quotes ",
+ cmSystemTools::Error("Could not parse command line with quotes " +
command);
}
}
@@ -182,7 +182,7 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
}
cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);
- const char* cmd[] = { command, 0 };
+ const char* cmd[] = { command.c_str(), nullptr };
cmsysProcess_SetCommand(cp, cmd);
#else
std::string commandInDir;
@@ -197,7 +197,7 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
# ifndef __VMS
commandInDir += " 2>&1";
# endif
- command = commandInDir.c_str();
+ command = commandInDir;
if (verbose) {
cmSystemTools::Stdout("running ");
cmSystemTools::Stdout(command);
@@ -205,7 +205,7 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
}
fflush(stdout);
fflush(stderr);
- const char* cmd[] = { "/bin/sh", "-c", command, nullptr };
+ const char* cmd[] = { "/bin/sh", "-c", command.c_str(), nullptr };
cmsysProcess_SetCommand(cp, cmd);
#endif
diff --git a/Source/cmExecProgramCommand.h b/Source/cmExecProgramCommand.h
index dc5da740d..ae0fa9b84 100644
--- a/Source/cmExecProgramCommand.h
+++ b/Source/cmExecProgramCommand.h
@@ -37,7 +37,7 @@ public:
cmExecutionStatus& status) override;
private:
- static bool RunCommand(const char* command, std::string& output, int& retVal,
+ static bool RunCommand(std::string command, std::string& output, int& retVal,
const char* directory = nullptr, bool verbose = true,
Encoding encoding = cmProcessOutput::Auto);
};
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index 8c67cdb4e..494afbb55 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -2,13 +2,17 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmExecuteProcessCommand.h"
+#include "cm_static_string_view.hxx"
#include "cmsys/Process.h"
+#include <algorithm>
#include <ctype.h> /* isspace */
-#include <sstream>
+#include <iostream>
#include <stdio.h>
#include "cmAlgorithms.h"
+#include "cmArgumentParser.h"
#include "cmMakefile.h"
+#include "cmMessageType.h"
#include "cmProcessOutput.h"
#include "cmSystemTools.h"
@@ -32,173 +36,108 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
this->SetError("called with incorrect number of arguments");
return false;
}
- std::vector<std::vector<const char*>> cmds;
- std::string arguments;
- bool doing_command = false;
- size_t command_index = 0;
- bool output_quiet = false;
- bool error_quiet = false;
- bool output_strip_trailing_whitespace = false;
- bool error_strip_trailing_whitespace = false;
- std::string timeout_string;
- std::string input_file;
- std::string output_file;
- std::string error_file;
- std::string output_variable;
- std::string error_variable;
- std::string result_variable;
- std::string results_variable;
- std::string working_directory;
- cmProcessOutput::Encoding encoding = cmProcessOutput::None;
- for (size_t i = 0; i < args.size(); ++i) {
- if (args[i] == "COMMAND") {
- doing_command = true;
- command_index = cmds.size();
- cmds.emplace_back();
- } else if (args[i] == "OUTPUT_VARIABLE") {
- doing_command = false;
- if (++i < args.size()) {
- output_variable = args[i];
- } else {
- this->SetError(" called with no value for OUTPUT_VARIABLE.");
- return false;
- }
- } else if (args[i] == "ERROR_VARIABLE") {
- doing_command = false;
- if (++i < args.size()) {
- error_variable = args[i];
- } else {
- this->SetError(" called with no value for ERROR_VARIABLE.");
- return false;
- }
- } else if (args[i] == "RESULT_VARIABLE") {
- doing_command = false;
- if (++i < args.size()) {
- result_variable = args[i];
- } else {
- this->SetError(" called with no value for RESULT_VARIABLE.");
- return false;
- }
- } else if (args[i] == "RESULTS_VARIABLE") {
- doing_command = false;
- if (++i < args.size()) {
- results_variable = args[i];
- } else {
- this->SetError(" called with no value for RESULTS_VARIABLE.");
- return false;
- }
- } else if (args[i] == "WORKING_DIRECTORY") {
- doing_command = false;
- if (++i < args.size()) {
- working_directory = args[i];
- } else {
- this->SetError(" called with no value for WORKING_DIRECTORY.");
- return false;
- }
- } else if (args[i] == "INPUT_FILE") {
- doing_command = false;
- if (++i < args.size()) {
- input_file = args[i];
- } else {
- this->SetError(" called with no value for INPUT_FILE.");
- return false;
- }
- } else if (args[i] == "OUTPUT_FILE") {
- doing_command = false;
- if (++i < args.size()) {
- output_file = args[i];
- } else {
- this->SetError(" called with no value for OUTPUT_FILE.");
- return false;
- }
- } else if (args[i] == "ERROR_FILE") {
- doing_command = false;
- if (++i < args.size()) {
- error_file = args[i];
- } else {
- this->SetError(" called with no value for ERROR_FILE.");
- return false;
- }
- } else if (args[i] == "TIMEOUT") {
- doing_command = false;
- if (++i < args.size()) {
- timeout_string = args[i];
- } else {
- this->SetError(" called with no value for TIMEOUT.");
- return false;
- }
- } else if (args[i] == "OUTPUT_QUIET") {
- doing_command = false;
- output_quiet = true;
- } else if (args[i] == "ERROR_QUIET") {
- doing_command = false;
- error_quiet = true;
- } else if (args[i] == "OUTPUT_STRIP_TRAILING_WHITESPACE") {
- doing_command = false;
- output_strip_trailing_whitespace = true;
- } else if (args[i] == "ERROR_STRIP_TRAILING_WHITESPACE") {
- doing_command = false;
- error_strip_trailing_whitespace = true;
- } else if (args[i] == "ENCODING") {
- doing_command = false;
- if (++i < args.size()) {
- encoding = cmProcessOutput::FindEncoding(args[i]);
- } else {
- this->SetError(" called with no value for ENCODING.");
- return false;
- }
- } else if (doing_command) {
- cmds[command_index].push_back(args[i].c_str());
- } else {
- std::ostringstream e;
- e << " given unknown argument \"" << args[i] << "\".";
- this->SetError(e.str());
- return false;
- }
+
+ struct Arguments
+ {
+ std::vector<std::vector<std::string>> Commands;
+ std::string OutputVariable;
+ std::string ErrorVariable;
+ std::string ResultVariable;
+ std::string ResultsVariable;
+ std::string WorkingDirectory;
+ std::string InputFile;
+ std::string OutputFile;
+ std::string ErrorFile;
+ std::string Timeout;
+ std::string CommandEcho;
+ bool OutputQuiet = false;
+ bool ErrorQuiet = false;
+ bool OutputStripTrailingWhitespace = false;
+ bool ErrorStripTrailingWhitespace = false;
+ std::string Encoding;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("COMMAND"_s, &Arguments::Commands)
+ .Bind("COMMAND_ECHO"_s, &Arguments::CommandEcho)
+ .Bind("OUTPUT_VARIABLE"_s, &Arguments::OutputVariable)
+ .Bind("ERROR_VARIABLE"_s, &Arguments::ErrorVariable)
+ .Bind("RESULT_VARIABLE"_s, &Arguments::ResultVariable)
+ .Bind("RESULTS_VARIABLE"_s, &Arguments::ResultsVariable)
+ .Bind("WORKING_DIRECTORY"_s, &Arguments::WorkingDirectory)
+ .Bind("INPUT_FILE"_s, &Arguments::InputFile)
+ .Bind("OUTPUT_FILE"_s, &Arguments::OutputFile)
+ .Bind("ERROR_FILE"_s, &Arguments::ErrorFile)
+ .Bind("TIMEOUT"_s, &Arguments::Timeout)
+ .Bind("OUTPUT_QUIET"_s, &Arguments::OutputQuiet)
+ .Bind("ERROR_QUIET"_s, &Arguments::ErrorQuiet)
+ .Bind("OUTPUT_STRIP_TRAILING_WHITESPACE"_s,
+ &Arguments::OutputStripTrailingWhitespace)
+ .Bind("ERROR_STRIP_TRAILING_WHITESPACE"_s,
+ &Arguments::ErrorStripTrailingWhitespace)
+ .Bind("ENCODING"_s, &Arguments::Encoding);
+
+ std::vector<std::string> unparsedArguments;
+ std::vector<std::string> keywordsMissingValue;
+ Arguments const arguments =
+ parser.Parse(args, &unparsedArguments, &keywordsMissingValue);
+
+ if (!keywordsMissingValue.empty()) {
+ this->SetError(" called with no value for " +
+ keywordsMissingValue.front() + ".");
+ return false;
+ }
+ if (!unparsedArguments.empty()) {
+ this->SetError(" given unknown argument \"" + unparsedArguments.front() +
+ "\".");
+ return false;
}
- if (!this->Makefile->CanIWriteThisFile(output_file)) {
- std::string e = "attempted to output into a file: " + output_file +
- " into a source directory.";
- this->SetError(e);
+ if (!this->Makefile->CanIWriteThisFile(arguments.OutputFile)) {
+ this->SetError("attempted to output into a file: " + arguments.OutputFile +
+ " into a source directory.");
cmSystemTools::SetFatalErrorOccured();
return false;
}
// Check for commands given.
- if (cmds.empty()) {
+ if (arguments.Commands.empty()) {
this->SetError(" called with no COMMAND argument.");
return false;
}
- for (auto& cmd : cmds) {
+ for (std::vector<std::string> const& cmd : arguments.Commands) {
if (cmd.empty()) {
this->SetError(" given COMMAND argument with no value.");
return false;
}
- // Add the null terminating pointer to the command argument list.
- cmd.push_back(nullptr);
}
// Parse the timeout string.
double timeout = -1;
- if (!timeout_string.empty()) {
- if (sscanf(timeout_string.c_str(), "%lg", &timeout) != 1) {
+ if (!arguments.Timeout.empty()) {
+ if (sscanf(arguments.Timeout.c_str(), "%lg", &timeout) != 1) {
this->SetError(" called with TIMEOUT value that could not be parsed.");
return false;
}
}
-
// Create a process instance.
- cmsysProcess* cp = cmsysProcess_New();
+ std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp_ptr(
+ cmsysProcess_New(), cmsysProcess_Delete);
+ cmsysProcess* cp = cp_ptr.get();
// Set the command sequence.
- for (auto const& cmd : cmds) {
- cmsysProcess_AddCommand(cp, &*cmd.begin());
+ for (std::vector<std::string> const& cmd : arguments.Commands) {
+ std::vector<const char*> argv(cmd.size() + 1);
+ std::transform(cmd.begin(), cmd.end(), argv.begin(),
+ [](std::string const& s) { return s.c_str(); });
+ argv.back() = nullptr;
+ cmsysProcess_AddCommand(cp, argv.data());
}
// Set the process working directory.
- if (!working_directory.empty()) {
- cmsysProcess_SetWorkingDirectory(cp, working_directory.c_str());
+ if (!arguments.WorkingDirectory.empty()) {
+ cmsysProcess_SetWorkingDirectory(cp, arguments.WorkingDirectory.c_str());
}
// Always hide the process window.
@@ -206,22 +145,24 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
// Check the output variables.
bool merge_output = false;
- if (!input_file.empty()) {
- cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN, input_file.c_str());
+ if (!arguments.InputFile.empty()) {
+ cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN,
+ arguments.InputFile.c_str());
}
- if (!output_file.empty()) {
+ if (!arguments.OutputFile.empty()) {
cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDOUT,
- output_file.c_str());
+ arguments.OutputFile.c_str());
}
- if (!error_file.empty()) {
- if (error_file == output_file) {
+ if (!arguments.ErrorFile.empty()) {
+ if (arguments.ErrorFile == arguments.OutputFile) {
merge_output = true;
} else {
cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR,
- error_file.c_str());
+ arguments.ErrorFile.c_str());
}
}
- if (!output_variable.empty() && output_variable == error_variable) {
+ if (!arguments.OutputVariable.empty() &&
+ arguments.OutputVariable == arguments.ErrorVariable) {
merge_output = true;
}
if (merge_output) {
@@ -233,6 +174,51 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
cmsysProcess_SetTimeout(cp, timeout);
}
+ bool echo_stdout = false;
+ bool echo_stderr = false;
+ bool echo_output_from_variable = true;
+ std::string echo_output =
+ this->Makefile->GetSafeDefinition("CMAKE_EXECUTE_PROCESS_COMMAND_ECHO");
+ if (!arguments.CommandEcho.empty()) {
+ echo_output_from_variable = false;
+ echo_output = arguments.CommandEcho;
+ }
+
+ if (!echo_output.empty()) {
+ if (echo_output == "STDERR") {
+ echo_stderr = true;
+ } else if (echo_output == "STDOUT") {
+ echo_stdout = true;
+ } else if (echo_output != "NONE") {
+ std::string error;
+ if (echo_output_from_variable) {
+ error = "CMAKE_EXECUTE_PROCESS_COMMAND_ECHO set to '";
+ } else {
+ error = " called with '";
+ }
+ error += echo_output;
+ error += "' expected STDERR|STDOUT|NONE";
+ if (!echo_output_from_variable) {
+ error += " for COMMAND_ECHO.";
+ }
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, error);
+ return true;
+ }
+ }
+ if (echo_stdout || echo_stderr) {
+ std::string command;
+ for (auto& cmd : arguments.Commands) {
+ command += "'";
+ command += cmJoin(cmd, "' '");
+ command += "'";
+ command += "\n";
+ }
+ if (echo_stdout) {
+ std::cout << command;
+ } else if (echo_stderr) {
+ std::cerr << command;
+ }
+ }
// Start the process.
cmsysProcess_Execute(cp);
@@ -242,19 +228,20 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
int length;
char* data;
int p;
- cmProcessOutput processOutput(encoding);
+ cmProcessOutput processOutput(
+ cmProcessOutput::FindEncoding(arguments.Encoding));
std::string strdata;
while ((p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) {
// Put the output in the right place.
- if (p == cmsysProcess_Pipe_STDOUT && !output_quiet) {
- if (output_variable.empty()) {
+ if (p == cmsysProcess_Pipe_STDOUT && !arguments.OutputQuiet) {
+ if (arguments.OutputVariable.empty()) {
processOutput.DecodeText(data, length, strdata, 1);
cmSystemTools::Stdout(strdata);
} else {
cmExecuteProcessCommandAppend(tempOutput, data, length);
}
- } else if (p == cmsysProcess_Pipe_STDERR && !error_quiet) {
- if (error_variable.empty()) {
+ } else if (p == cmsysProcess_Pipe_STDERR && !arguments.ErrorQuiet) {
+ if (arguments.ErrorVariable.empty()) {
processOutput.DecodeText(data, length, strdata, 2);
cmSystemTools::Stderr(strdata);
} else {
@@ -262,13 +249,13 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
}
}
}
- if (!output_quiet && output_variable.empty()) {
+ if (!arguments.OutputQuiet && arguments.OutputVariable.empty()) {
processOutput.DecodeText(std::string(), strdata, 1);
if (!strdata.empty()) {
cmSystemTools::Stdout(strdata);
}
}
- if (!error_quiet && error_variable.empty()) {
+ if (!arguments.ErrorQuiet && arguments.ErrorVariable.empty()) {
processOutput.DecodeText(std::string(), strdata, 2);
if (!strdata.empty()) {
cmSystemTools::Stderr(strdata);
@@ -281,46 +268,49 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
processOutput.DecodeText(tempError, tempError);
// Fix the text in the output strings.
- cmExecuteProcessCommandFixText(tempOutput, output_strip_trailing_whitespace);
- cmExecuteProcessCommandFixText(tempError, error_strip_trailing_whitespace);
+ cmExecuteProcessCommandFixText(tempOutput,
+ arguments.OutputStripTrailingWhitespace);
+ cmExecuteProcessCommandFixText(tempError,
+ arguments.ErrorStripTrailingWhitespace);
// Store the output obtained.
- if (!output_variable.empty() && !tempOutput.empty()) {
- this->Makefile->AddDefinition(output_variable, &*tempOutput.begin());
+ if (!arguments.OutputVariable.empty() && !tempOutput.empty()) {
+ this->Makefile->AddDefinition(arguments.OutputVariable, tempOutput.data());
}
- if (!merge_output && !error_variable.empty() && !tempError.empty()) {
- this->Makefile->AddDefinition(error_variable, &*tempError.begin());
+ if (!merge_output && !arguments.ErrorVariable.empty() &&
+ !tempError.empty()) {
+ this->Makefile->AddDefinition(arguments.ErrorVariable, tempError.data());
}
// Store the result of running the process.
- if (!result_variable.empty()) {
+ if (!arguments.ResultVariable.empty()) {
switch (cmsysProcess_GetState(cp)) {
case cmsysProcess_State_Exited: {
int v = cmsysProcess_GetExitValue(cp);
char buf[16];
sprintf(buf, "%d", v);
- this->Makefile->AddDefinition(result_variable, buf);
+ this->Makefile->AddDefinition(arguments.ResultVariable, buf);
} break;
case cmsysProcess_State_Exception:
- this->Makefile->AddDefinition(result_variable,
+ this->Makefile->AddDefinition(arguments.ResultVariable,
cmsysProcess_GetExceptionString(cp));
break;
case cmsysProcess_State_Error:
- this->Makefile->AddDefinition(result_variable,
+ this->Makefile->AddDefinition(arguments.ResultVariable,
cmsysProcess_GetErrorString(cp));
break;
case cmsysProcess_State_Expired:
- this->Makefile->AddDefinition(result_variable,
+ this->Makefile->AddDefinition(arguments.ResultVariable,
"Process terminated due to timeout");
break;
}
}
// Store the result of running the processes.
- if (!results_variable.empty()) {
+ if (!arguments.ResultsVariable.empty()) {
switch (cmsysProcess_GetState(cp)) {
case cmsysProcess_State_Exited: {
std::vector<std::string> res;
- for (size_t i = 0; i < cmds.size(); ++i) {
+ for (size_t i = 0; i < arguments.Commands.size(); ++i) {
switch (cmsysProcess_GetStateByIndex(cp, static_cast<int>(i))) {
case kwsysProcess_StateByIndex_Exited: {
int exitCode =
@@ -339,27 +329,24 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
break;
}
}
- this->Makefile->AddDefinition(results_variable,
+ this->Makefile->AddDefinition(arguments.ResultsVariable,
cmJoin(res, ";").c_str());
} break;
case cmsysProcess_State_Exception:
- this->Makefile->AddDefinition(results_variable,
+ this->Makefile->AddDefinition(arguments.ResultsVariable,
cmsysProcess_GetExceptionString(cp));
break;
case cmsysProcess_State_Error:
- this->Makefile->AddDefinition(results_variable,
+ this->Makefile->AddDefinition(arguments.ResultsVariable,
cmsysProcess_GetErrorString(cp));
break;
case cmsysProcess_State_Expired:
- this->Makefile->AddDefinition(results_variable,
+ this->Makefile->AddDefinition(arguments.ResultsVariable,
"Process terminated due to timeout");
break;
}
}
- // Delete the process instance.
- cmsysProcess_Delete(cp);
-
return true;
}
@@ -406,5 +393,5 @@ void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data,
--length;
}
#endif
- output.insert(output.end(), data, data + length);
+ cmAppend(output, data, data + length);
}
diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h
index ada270996..0a1e75582 100644
--- a/Source/cmExportBuildFileGenerator.h
+++ b/Source/cmExportBuildFileGenerator.h
@@ -5,6 +5,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cmAlgorithms.h"
#include "cmExportFileGenerator.h"
#include "cmStateTypes.h"
@@ -39,7 +40,7 @@ public:
void GetTargets(std::vector<std::string>& targets) const;
void AppendTargets(std::vector<std::string> const& targets)
{
- this->Targets.insert(this->Targets.end(), targets.begin(), targets.end());
+ cmAppend(this->Targets, targets);
}
void SetExportSet(cmExportSet*);
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
index 722831a7f..a849aa246 100644
--- a/Source/cmExportCommand.cxx
+++ b/Source/cmExportCommand.cxx
@@ -2,10 +2,15 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmExportCommand.h"
+#include "cm_static_string_view.hxx"
#include "cmsys/RegularExpression.hxx"
+
+#include <algorithm>
#include <map>
#include <sstream>
+#include <utility>
+#include "cmArgumentParser.h"
#include "cmExportBuildAndroidMKGenerator.h"
#include "cmExportBuildFileGenerator.h"
#include "cmExportSetMap.h"
@@ -13,10 +18,12 @@
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmPolicies.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
+class cmExportSet;
class cmExecutionStatus;
#if defined(__HAIKU__)
@@ -24,19 +31,6 @@ class cmExecutionStatus;
# include <StorageDefs.h>
#endif
-cmExportCommand::cmExportCommand()
- : Targets(&Helper, "TARGETS")
- , Append(&Helper, "APPEND", &ArgumentGroup)
- , ExportSetName(&Helper, "EXPORT", &ArgumentGroup)
- , Namespace(&Helper, "NAMESPACE", &ArgumentGroup)
- , Filename(&Helper, "FILE", &ArgumentGroup)
- , ExportOld(&Helper, "EXPORT_LINK_INTERFACE_LIBRARIES", &ArgumentGroup)
- , AndroidMKFile(&Helper, "ANDROID_MK")
-{
- this->ExportSet = nullptr;
-}
-
-// cmExportCommand
bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
cmExecutionStatus&)
{
@@ -48,45 +42,64 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
if (args[0] == "PACKAGE") {
return this->HandlePackage(args);
}
+
+ struct Arguments
+ {
+ std::string ExportSetName;
+ std::vector<std::string> Targets;
+ std::string Namespace;
+ std::string Filename;
+ std::string AndroidMKFile;
+ bool Append = false;
+ bool ExportOld = false;
+ };
+
+ auto parser = cmArgumentParser<Arguments>{}
+ .Bind("NAMESPACE"_s, &Arguments::Namespace)
+ .Bind("FILE"_s, &Arguments::Filename);
+
if (args[0] == "EXPORT") {
- this->ExportSetName.Follows(nullptr);
- this->ArgumentGroup.Follows(&this->ExportSetName);
+ parser.Bind("EXPORT"_s, &Arguments::ExportSetName);
} else {
- this->Targets.Follows(nullptr);
- this->ArgumentGroup.Follows(&this->Targets);
+ parser.Bind("TARGETS"_s, &Arguments::Targets);
+ parser.Bind("ANDROID_MK"_s, &Arguments::AndroidMKFile);
+ parser.Bind("APPEND"_s, &Arguments::Append);
+ parser.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, &Arguments::ExportOld);
}
std::vector<std::string> unknownArgs;
- this->Helper.Parse(&args, &unknownArgs);
+ std::vector<std::string> keywordsMissingValue;
+ Arguments const arguments =
+ parser.Parse(args, &unknownArgs, &keywordsMissingValue);
if (!unknownArgs.empty()) {
- this->SetError("Unknown arguments.");
+ this->SetError("Unknown argument: \"" + unknownArgs.front() + "\".");
return false;
}
std::string fname;
bool android = false;
- if (this->AndroidMKFile.WasFound()) {
- fname = this->AndroidMKFile.GetString();
+ if (!arguments.AndroidMKFile.empty()) {
+ fname = arguments.AndroidMKFile;
android = true;
}
- if (!this->Filename.WasFound() && fname.empty()) {
+ if (arguments.Filename.empty() && fname.empty()) {
if (args[0] != "EXPORT") {
this->SetError("FILE <filename> option missing.");
return false;
}
- fname = this->ExportSetName.GetString() + ".cmake";
+ fname = arguments.ExportSetName + ".cmake";
} else if (fname.empty()) {
// Make sure the file has a .cmake extension.
- if (cmSystemTools::GetFilenameLastExtension(this->Filename.GetCString()) !=
+ if (cmSystemTools::GetFilenameLastExtension(arguments.Filename) !=
".cmake") {
std::ostringstream e;
- e << "FILE option given filename \"" << this->Filename.GetString()
+ e << "FILE option given filename \"" << arguments.Filename
<< "\" which does not have an extension of \".cmake\".\n";
this->SetError(e.str());
return false;
}
- fname = this->Filename.GetString();
+ fname = arguments.Filename;
}
// Get the file to write.
@@ -108,33 +121,22 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
+ cmExportSet* ExportSet = nullptr;
if (args[0] == "EXPORT") {
- if (this->Append.IsEnabled()) {
- std::ostringstream e;
- e << "EXPORT signature does not recognise the APPEND option.";
- this->SetError(e.str());
- return false;
- }
-
- if (this->ExportOld.IsEnabled()) {
- std::ostringstream e;
- e << "EXPORT signature does not recognise the "
- "EXPORT_LINK_INTERFACE_LIBRARIES option.";
- this->SetError(e.str());
- return false;
- }
-
cmExportSetMap& setMap = gg->GetExportSets();
- std::string setName = this->ExportSetName.GetString();
- if (setMap.find(setName) == setMap.end()) {
+ auto const it = setMap.find(arguments.ExportSetName);
+ if (it == setMap.end()) {
std::ostringstream e;
- e << "Export set \"" << setName << "\" not found.";
+ e << "Export set \"" << arguments.ExportSetName << "\" not found.";
this->SetError(e.str());
return false;
}
- this->ExportSet = setMap[setName];
- } else if (this->Targets.WasFound()) {
- for (std::string const& currentTarget : this->Targets.GetVector()) {
+ ExportSet = it->second;
+ } else if (!arguments.Targets.empty() ||
+ std::find(keywordsMissingValue.begin(),
+ keywordsMissingValue.end(),
+ "TARGETS") != keywordsMissingValue.end()) {
+ for (std::string const& currentTarget : arguments.Targets) {
if (this->Makefile->IsAlias(currentTarget)) {
std::ostringstream e;
e << "given ALIAS target \"" << currentTarget
@@ -158,7 +160,7 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
}
targets.push_back(currentTarget);
}
- if (this->Append.IsEnabled()) {
+ if (arguments.Append) {
if (cmExportBuildFileGenerator* ebfg =
gg->GetExportedTargetsFile(fname)) {
ebfg->AppendTargets(targets);
@@ -178,15 +180,15 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
ebfg = new cmExportBuildFileGenerator;
}
ebfg->SetExportFile(fname.c_str());
- ebfg->SetNamespace(this->Namespace.GetCString());
- ebfg->SetAppendMode(this->Append.IsEnabled());
- if (this->ExportSet) {
- ebfg->SetExportSet(this->ExportSet);
+ ebfg->SetNamespace(arguments.Namespace);
+ ebfg->SetAppendMode(arguments.Append);
+ if (ExportSet != nullptr) {
+ ebfg->SetExportSet(ExportSet);
} else {
ebfg->SetTargets(targets);
}
this->Makefile->AddExportBuildFileGenerator(ebfg);
- ebfg->SetExportOld(this->ExportOld.IsEnabled());
+ ebfg->SetExportOld(arguments.ExportOld);
// Compute the set of configurations exported.
std::vector<std::string> configurationTypes;
@@ -197,7 +199,7 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args,
for (std::string const& ct : configurationTypes) {
ebfg->AddConfiguration(ct);
}
- if (this->ExportSet) {
+ if (ExportSet != nullptr) {
gg->AddBuildExportExportSet(ebfg);
} else {
gg->AddBuildExportSet(ebfg);
@@ -243,10 +245,23 @@ bool cmExportCommand::HandlePackage(std::vector<std::string> const& args)
return false;
}
- // If the CMAKE_EXPORT_NO_PACKAGE_REGISTRY variable is set the command
- // export(PACKAGE) does nothing.
- if (this->Makefile->IsOn("CMAKE_EXPORT_NO_PACKAGE_REGISTRY")) {
- return true;
+ // CMP0090 decides both the default and what variable changes it.
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0090)) {
+ case cmPolicies::WARN:
+ case cmPolicies::OLD:
+ // Default is to export, but can be disabled.
+ if (this->Makefile->IsOn("CMAKE_EXPORT_NO_PACKAGE_REGISTRY")) {
+ return true;
+ }
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Default is to not export, but can be enabled.
+ if (!this->Makefile->IsOn("CMAKE_EXPORT_PACKAGE_REGISTRY")) {
+ return true;
+ }
+ break;
}
// We store the current build directory in the registry as a value
diff --git a/Source/cmExportCommand.h b/Source/cmExportCommand.h
index a5c6751bf..99f9932b9 100644
--- a/Source/cmExportCommand.h
+++ b/Source/cmExportCommand.h
@@ -9,21 +9,12 @@
#include <vector>
#include "cmCommand.h"
-#include "cmCommandArgumentsHelper.h"
class cmExecutionStatus;
-class cmExportSet;
-/** \class cmExportLibraryDependenciesCommand
- * \brief Add a test to the lists of tests to run.
- *
- * cmExportLibraryDependenciesCommand adds a test to the list of tests to run
- *
- */
class cmExportCommand : public cmCommand
{
public:
- cmExportCommand();
/**
* This is a virtual constructor for the command.
*/
@@ -37,21 +28,6 @@ public:
cmExecutionStatus& status) override;
private:
- cmCommandArgumentsHelper Helper;
- cmCommandArgumentGroup ArgumentGroup;
- cmCAStringVector Targets;
- cmCAEnabler Append;
- cmCAString ExportSetName;
- cmCAString Namespace;
- cmCAString Filename;
- cmCAEnabler ExportOld;
- cmCAString AndroidMKFile;
-
- cmExportSet* ExportSet;
-
- friend class cmExportBuildFileGenerator;
- std::string ErrorMessage;
-
bool HandlePackage(std::vector<std::string> const& args);
void StorePackageRegistryWin(std::string const& package, const char* content,
const char* hash);
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index c8f743acd..a12e0c48d 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -70,8 +70,9 @@ bool cmExportFileGenerator::GenerateImportFile()
std::unique_ptr<cmsys::ofstream> foutPtr;
if (this->AppendMode) {
// Open for append.
+ auto openmodeApp = std::ios::app;
foutPtr = cm::make_unique<cmsys::ofstream>(this->MainImportFile.c_str(),
- std::ios::app);
+ openmodeApp);
} else {
// Generate atomically and with copy-if-different.
std::unique_ptr<cmGeneratedFileStream> ap(
diff --git a/Source/cmExportLibraryDependenciesCommand.cxx b/Source/cmExportLibraryDependenciesCommand.cxx
index b4b2962b1..b60a0533c 100644
--- a/Source/cmExportLibraryDependenciesCommand.cxx
+++ b/Source/cmExportLibraryDependenciesCommand.cxx
@@ -50,8 +50,9 @@ void cmExportLibraryDependenciesCommand::ConstFinalPass() const
// Use copy-if-different if not appending.
std::unique_ptr<cmsys::ofstream> foutPtr;
if (this->Append) {
+ const auto openmodeApp = std::ios::app;
foutPtr =
- cm::make_unique<cmsys::ofstream>(this->Filename.c_str(), std::ios::app);
+ cm::make_unique<cmsys::ofstream>(this->Filename.c_str(), openmodeApp);
} else {
std::unique_ptr<cmGeneratedFileStream> ap(
new cmGeneratedFileStream(this->Filename, true));
@@ -61,7 +62,7 @@ void cmExportLibraryDependenciesCommand::ConstFinalPass() const
std::ostream& fout = *foutPtr;
if (!fout) {
- cmSystemTools::Error("Error Writing ", this->Filename.c_str());
+ cmSystemTools::Error("Error Writing " + this->Filename);
cmSystemTools::ReportLastSystemError("");
return;
}
@@ -75,8 +76,7 @@ void cmExportLibraryDependenciesCommand::ConstFinalPass() const
std::map<std::string, std::string> libDepsNew;
std::map<std::string, std::string> libTypes;
for (cmMakefile* local : locals) {
- const cmTargets& tgts = local->GetTargets();
- for (auto const& tgt : tgts) {
+ for (auto const& tgt : local->GetTargets()) {
// Get the current target.
cmTarget const& target = tgt.second;
diff --git a/Source/cmExportSet.h b/Source/cmExportSet.h
index 0ef306f63..d654c1285 100644
--- a/Source/cmExportSet.h
+++ b/Source/cmExportSet.h
@@ -25,6 +25,9 @@ public:
/// Destructor
~cmExportSet();
+ cmExportSet(const cmExportSet&) = delete;
+ cmExportSet& operator=(const cmExportSet&) = delete;
+
void Compute(cmLocalGenerator* lg);
void AddTargetExport(cmTargetExport* tgt);
diff --git a/Source/cmExportSetMap.cxx b/Source/cmExportSetMap.cxx
index 074082835..293e80cf9 100644
--- a/Source/cmExportSetMap.cxx
+++ b/Source/cmExportSetMap.cxx
@@ -23,6 +23,8 @@ void cmExportSetMap::clear()
this->derived::clear();
}
+cmExportSetMap::cmExportSetMap() = default;
+
cmExportSetMap::~cmExportSetMap()
{
this->clear();
diff --git a/Source/cmExportSetMap.h b/Source/cmExportSetMap.h
index 0f71c790c..385373240 100644
--- a/Source/cmExportSetMap.h
+++ b/Source/cmExportSetMap.h
@@ -25,8 +25,13 @@ public:
void clear();
+ cmExportSetMap();
+
/// Overloaded destructor deletes all member export sets.
~cmExportSetMap();
+
+ cmExportSetMap(const cmExportSetMap&) = delete;
+ cmExportSetMap& operator=(const cmExportSetMap&) = delete;
};
#endif
diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h
index 4438f2803..a472a0691 100644
--- a/Source/cmExternalMakefileProjectGenerator.h
+++ b/Source/cmExternalMakefileProjectGenerator.h
@@ -31,13 +31,13 @@ public:
virtual void EnableLanguage(std::vector<std::string> const& languages,
cmMakefile*, bool optional);
- ///! set the global generator which will generate the makefiles
+ //! set the global generator which will generate the makefiles
virtual void SetGlobalGenerator(cmGlobalGenerator* generator)
{
this->GlobalGenerator = generator;
}
- ///! Return the list of global generators supported by this extra generator
+ //! Return the list of global generators supported by this extra generator
const std::vector<std::string>& GetSupportedGlobalGenerators() const
{
return this->SupportedGlobalGenerators;
@@ -49,7 +49,7 @@ public:
static std::string CreateFullGeneratorName(
const std::string& globalGenerator, const std::string& extraGenerator);
- ///! Generate the project files, the Makefiles have already been generated
+ //! Generate the project files, the Makefiles have already been generated
virtual void Generate() = 0;
void SetName(const std::string& n) { Name = n; }
@@ -59,9 +59,9 @@ public:
bool dryRun);
protected:
- ///! Contains the names of the global generators support by this generator.
+ //! Contains the names of the global generators support by this generator.
std::vector<std::string> SupportedGlobalGenerators;
- ///! the global generator which creates the makefiles
+ //! the global generator which creates the makefiles
const cmGlobalGenerator* GlobalGenerator = nullptr;
std::string Name;
diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx
index e408de384..f47744b60 100644
--- a/Source/cmExtraCodeBlocksGenerator.cxx
+++ b/Source/cmExtraCodeBlocksGenerator.cxx
@@ -13,6 +13,7 @@
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
@@ -208,9 +209,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
// Collect all files
std::vector<std::string> listFiles;
for (cmLocalGenerator* lg : it.second) {
- const std::vector<std::string>& files =
- lg->GetMakefile()->GetListFiles();
- listFiles.insert(listFiles.end(), files.begin(), files.end());
+ cmAppend(listFiles, lg->GetMakefile()->GetListFiles());
}
// Convert
@@ -247,8 +246,8 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
// figure out the compiler
std::string compiler = this->GetCBCompilerId(mf);
- std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
- const std::string makeArgs =
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& makeArgs =
mf->GetSafeDefinition("CMAKE_CODEBLOCKS_MAKE_ARGUMENTS");
cmXMLWriter xml(fout);
@@ -279,8 +278,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
xml.StartElement("Build");
- this->AppendTarget(xml, "all", nullptr, make.c_str(), lgs[0],
- compiler.c_str(), makeArgs);
+ this->AppendTarget(xml, "all", nullptr, make, lgs[0], compiler, makeArgs);
// add all executable and library targets and some of the GLOBAL
// and UTILITY targets
@@ -293,8 +291,8 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
// Only add the global targets from CMAKE_BINARY_DIR,
// not from the subdirs
if (lg->GetCurrentBinaryDirectory() == lg->GetBinaryDirectory()) {
- this->AppendTarget(xml, targetName, nullptr, make.c_str(), lg,
- compiler.c_str(), makeArgs);
+ this->AppendTarget(xml, targetName, nullptr, make, lg, compiler,
+ makeArgs);
}
} break;
case cmStateEnums::UTILITY:
@@ -309,8 +307,8 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
break;
}
- this->AppendTarget(xml, targetName, nullptr, make.c_str(), lg,
- compiler.c_str(), makeArgs);
+ this->AppendTarget(xml, targetName, nullptr, make, lg, compiler,
+ makeArgs);
break;
case cmStateEnums::EXECUTABLE:
case cmStateEnums::STATIC_LIBRARY:
@@ -318,12 +316,12 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
case cmStateEnums::MODULE_LIBRARY:
case cmStateEnums::OBJECT_LIBRARY: {
cmGeneratorTarget* gt = target;
- this->AppendTarget(xml, targetName, gt, make.c_str(), lg,
- compiler.c_str(), makeArgs);
+ this->AppendTarget(xml, targetName, gt, make, lg, compiler,
+ makeArgs);
std::string fastTarget = targetName;
fastTarget += "/fast";
- this->AppendTarget(xml, fastTarget, gt, make.c_str(), lg,
- compiler.c_str(), makeArgs);
+ this->AppendTarget(xml, fastTarget, gt, make, lg, compiler,
+ makeArgs);
} break;
default:
break;
@@ -377,7 +375,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
std::string const& fullPath = s->GetFullPath();
// Check file position relative to project root dir.
- const std::string& relative =
+ const std::string relative =
cmSystemTools::RelativePath(lg->GetSourceDirectory(), fullPath);
// Do not add this file if it has ".." in relative path and
// if CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable is on.
@@ -453,7 +451,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
}
// Add CMakeLists.txt
- tree.BuildUnit(xml, std::string(mf->GetHomeDirectory()) + "/");
+ tree.BuildUnit(xml, mf->GetHomeDirectory() + "/");
xml.EndElement(); // Project
xml.EndElement(); // CodeBlocks_project_file
@@ -488,8 +486,8 @@ std::string cmExtraCodeBlocksGenerator::CreateDummyTargetFile(
// Generate the xml code for one target.
void cmExtraCodeBlocksGenerator::AppendTarget(
cmXMLWriter& xml, const std::string& targetName, cmGeneratorTarget* target,
- const char* make, const cmLocalGenerator* lg, const char* compiler,
- const std::string& makeFlags)
+ const std::string& make, const cmLocalGenerator* lg,
+ const std::string& compiler, const std::string& makeFlags)
{
cmMakefile const* makefile = lg->GetMakefile();
std::string makefileName = lg->GetCurrentBinaryDirectory();
@@ -563,36 +561,32 @@ void cmExtraCodeBlocksGenerator::AppendTarget(
// the include directories for this target
std::vector<std::string> allIncludeDirs;
-
- std::vector<std::string> includes;
- lg->GetIncludeDirectories(includes, target, "C", buildType);
-
- allIncludeDirs.insert(allIncludeDirs.end(), includes.begin(),
- includes.end());
+ {
+ std::vector<std::string> includes;
+ lg->GetIncludeDirectories(includes, target, "C", buildType);
+ cmAppend(allIncludeDirs, includes);
+ }
std::string systemIncludeDirs = makefile->GetSafeDefinition(
"CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
if (!systemIncludeDirs.empty()) {
- std::vector<std::string> dirs;
- cmSystemTools::ExpandListArgument(systemIncludeDirs, dirs);
- allIncludeDirs.insert(allIncludeDirs.end(), dirs.begin(), dirs.end());
+ cmAppend(allIncludeDirs,
+ cmSystemTools::ExpandedListArgument(systemIncludeDirs));
}
systemIncludeDirs = makefile->GetSafeDefinition(
"CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
if (!systemIncludeDirs.empty()) {
- std::vector<std::string> dirs;
- cmSystemTools::ExpandListArgument(systemIncludeDirs, dirs);
- allIncludeDirs.insert(allIncludeDirs.end(), dirs.begin(), dirs.end());
+ cmAppend(allIncludeDirs,
+ cmSystemTools::ExpandedListArgument(systemIncludeDirs));
}
std::vector<std::string>::const_iterator end =
cmRemoveDuplicates(allIncludeDirs);
- for (std::vector<std::string>::const_iterator i = allIncludeDirs.begin();
- i != end; ++i) {
+ for (std::string const& str : cmMakeRange(allIncludeDirs.cbegin(), end)) {
xml.StartElement("Add");
- xml.Attribute("directory", *i);
+ xml.Attribute("directory", str);
xml.EndElement();
}
@@ -613,25 +607,23 @@ void cmExtraCodeBlocksGenerator::AppendTarget(
xml.StartElement("Build");
xml.Attribute(
"command",
- this->BuildMakeCommand(make, makefileName.c_str(), targetName, makeFlags));
+ this->BuildMakeCommand(make, makefileName, targetName, makeFlags));
xml.EndElement();
xml.StartElement("CompileFile");
- xml.Attribute("command",
- this->BuildMakeCommand(make, makefileName.c_str(), "\"$file\"",
- makeFlags));
+ xml.Attribute(
+ "command",
+ this->BuildMakeCommand(make, makefileName, "\"$file\"", makeFlags));
xml.EndElement();
xml.StartElement("Clean");
xml.Attribute(
- "command",
- this->BuildMakeCommand(make, makefileName.c_str(), "clean", makeFlags));
+ "command", this->BuildMakeCommand(make, makefileName, "clean", makeFlags));
xml.EndElement();
xml.StartElement("DistClean");
xml.Attribute(
- "command",
- this->BuildMakeCommand(make, makefileName.c_str(), "clean", makeFlags));
+ "command", this->BuildMakeCommand(make, makefileName, "clean", makeFlags));
xml.EndElement();
xml.EndElement(); // MakeCommands
@@ -725,8 +717,8 @@ int cmExtraCodeBlocksGenerator::GetCBTargetType(cmGeneratorTarget* target)
// Create the command line for building the given target using the selected
// make
std::string cmExtraCodeBlocksGenerator::BuildMakeCommand(
- const std::string& make, const char* makefile, const std::string& target,
- const std::string& makeFlags)
+ const std::string& make, const std::string& makefile,
+ const std::string& target, const std::string& makeFlags)
{
std::string command = make;
if (!makeFlags.empty()) {
@@ -747,7 +739,7 @@ std::string cmExtraCodeBlocksGenerator::BuildMakeCommand(
} else if (generator == "MinGW Makefiles") {
// no escaping of spaces in this case, see
// https://gitlab.kitware.com/cmake/cmake/issues/10014
- std::string makefileName = makefile;
+ std::string const& makefileName = makefile;
command += " -f \"";
command += makefileName;
command += "\" ";
diff --git a/Source/cmExtraCodeBlocksGenerator.h b/Source/cmExtraCodeBlocksGenerator.h
index be3af2562..173e28400 100644
--- a/Source/cmExtraCodeBlocksGenerator.h
+++ b/Source/cmExtraCodeBlocksGenerator.h
@@ -42,12 +42,13 @@ private:
std::string GetCBCompilerId(const cmMakefile* mf);
int GetCBTargetType(cmGeneratorTarget* target);
- std::string BuildMakeCommand(const std::string& make, const char* makefile,
+ std::string BuildMakeCommand(const std::string& make,
+ const std::string& makefile,
const std::string& target,
const std::string& makeFlags);
void AppendTarget(cmXMLWriter& xml, const std::string& targetName,
- cmGeneratorTarget* target, const char* make,
- const cmLocalGenerator* lg, const char* compiler,
+ cmGeneratorTarget* target, const std::string& make,
+ const cmLocalGenerator* lg, const std::string& compiler,
const std::string& makeFlags);
};
diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx
index 0773edcbd..6fe8c147f 100644
--- a/Source/cmExtraCodeLiteGenerator.cxx
+++ b/Source/cmExtraCodeLiteGenerator.cxx
@@ -628,8 +628,8 @@ std::string cmExtraCodeLiteGenerator::GetConfigurationName(
std::string cmExtraCodeLiteGenerator::GetBuildCommand(
const cmMakefile* mf, const std::string& targetName) const
{
- std::string generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
- std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
std::string buildCommand = make; // Default
std::ostringstream ss;
if (generator == "NMake Makefiles" || generator == "Ninja") {
@@ -669,8 +669,8 @@ std::string cmExtraCodeLiteGenerator::GetSingleFileBuildCommand(
const cmMakefile* mf) const
{
std::string buildCommand;
- std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
- std::string generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
if (generator == "Unix Makefiles" || generator == "MinGW Makefiles") {
std::ostringstream ss;
#if defined(_WIN32)
diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx
index e05f74ba5..aece3bc57 100644
--- a/Source/cmExtraEclipseCDT4Generator.cxx
+++ b/Source/cmExtraEclipseCDT4Generator.cxx
@@ -881,8 +881,8 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const
xml.Attribute("moduleId", "org.eclipse.cdt.make.core.buildtargets");
xml.StartElement("buildTargets");
emmited.clear();
- const std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
- const std::string makeArgs =
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& makeArgs =
mf->GetSafeDefinition("CMAKE_ECLIPSE_MAKE_ARGUMENTS");
cmGlobalGenerator* generator =
@@ -1079,7 +1079,8 @@ void cmExtraEclipseCDT4Generator::AppendStorageScanners(
cmXMLWriter& xml, const cmMakefile& makefile)
{
// we need the "make" and the C (or C++) compiler which are used, Alex
- std::string make = makefile.GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& make =
+ makefile.GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
std::string compiler = makefile.GetSafeDefinition("CMAKE_C_COMPILER");
std::string arg1 = makefile.GetSafeDefinition("CMAKE_C_COMPILER_ARG1");
if (compiler.empty()) {
diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx
index 23ba6b77f..877f10969 100644
--- a/Source/cmExtraKateGenerator.cxx
+++ b/Source/cmExtraKateGenerator.cxx
@@ -75,8 +75,8 @@ void cmExtraKateGenerator::WriteTargets(const cmLocalGenerator* lg,
cmGeneratedFileStream& fout) const
{
cmMakefile const* mf = lg->GetMakefile();
- const std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
- const std::string makeArgs =
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& makeArgs =
mf->GetSafeDefinition("CMAKE_KATE_MAKE_ARGUMENTS");
std::string const& homeOutputDir = lg->GetBinaryDirectory();
@@ -196,7 +196,7 @@ void cmExtraKateGenerator::AppendTarget(cmGeneratedFileStream& fout,
{
static char JsonSep = ' ';
- fout << "\t\t\t" << JsonSep << "{\"name\":\"" << target
+ fout << "\t\t\t" << JsonSep << R"({"name":")" << target
<< "\", "
"\"build_cmd\":\""
<< make << " -C \\\"" << (this->UseNinja ? homeOutputDir : path)
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
index 739a177bb..71c8fcd58 100644
--- a/Source/cmExtraSublimeTextGenerator.cxx
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -168,7 +168,7 @@ void cmExtraSublimeTextGenerator::AppendAllTargets(
const std::vector<cmLocalGenerator*>& lgs, const cmMakefile* mf,
cmGeneratedFileStream& fout, MapSourceFileFlags& sourceFileFlags)
{
- std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
std::string compiler;
if (!lgs.empty()) {
this->AppendTarget(fout, "all", lgs[0], nullptr, make.c_str(), mf,
@@ -263,7 +263,7 @@ void cmExtraSublimeTextGenerator::AppendTarget(
// Regular expression to extract compiler flags from a string
// https://gist.github.com/3944250
const char* regexString =
- "(^|[ ])-[DIOUWfgs][^= ]+(=\\\"[^\"]+\\\"|=[^\"][^ ]+)?";
+ R"((^|[ ])-[DIOUWfgs][^= ]+(=\"[^"]+\"|=[^"][^ ]+)?)";
flagRegex.compile(regexString);
std::string workString =
flagsString + " " + definesString + " " + includesString;
@@ -315,12 +315,12 @@ std::string cmExtraSublimeTextGenerator::BuildMakeCommand(
std::string generator = this->GlobalGenerator->GetName();
if (generator == "NMake Makefiles") {
std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
- command += ", \"/NOLOGO\", \"/f\", \"";
+ command += R"(, "/NOLOGO", "/f", ")";
command += makefileName + "\"";
command += ", \"" + target + "\"";
} else if (generator == "Ninja") {
std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
- command += ", \"-f\", \"";
+ command += R"(, "-f", ")";
command += makefileName + "\"";
command += ", \"" + target + "\"";
} else {
@@ -332,7 +332,7 @@ std::string cmExtraSublimeTextGenerator::BuildMakeCommand(
} else {
makefileName = cmSystemTools::ConvertToOutputPath(makefile);
}
- command += ", \"-f\", \"";
+ command += R"(, "-f", ")";
command += makefileName + "\"";
command += ", \"" + target + "\"";
}
diff --git a/Source/cmFLTKWrapUICommand.cxx b/Source/cmFLTKWrapUICommand.cxx
index 4b14d26d0..89629c768 100644
--- a/Source/cmFLTKWrapUICommand.cxx
+++ b/Source/cmFLTKWrapUICommand.cxx
@@ -6,6 +6,7 @@
#include "cmCustomCommandLines.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmSystemTools.h"
@@ -40,18 +41,17 @@ bool cmFLTKWrapUICommand::InitialPass(std::vector<std::string> const& args,
this->Makefile->AddIncludeDirectories(outputDirectories);
}
- for (std::vector<std::string>::const_iterator i = (args.begin() + 1);
- i != args.end(); i++) {
- cmSourceFile* curr = this->Makefile->GetSource(*i);
+ for (std::string const& arg : cmMakeRange(args).advance(1)) {
+ cmSourceFile* curr = this->Makefile->GetSource(arg);
// if we should use the source GUI
// to generate .cxx and .h files
if (!curr || !curr->GetPropertyAsBool("WRAP_EXCLUDE")) {
std::string outName = outputDirectory;
outName += "/";
- outName += cmSystemTools::GetFilenameWithoutExtension(*i);
+ outName += cmSystemTools::GetFilenameWithoutExtension(arg);
std::string hname = outName;
hname += ".h";
- std::string origname = cdir + "/" + *i;
+ std::string origname = cdir + "/" + arg;
// add starting depends
std::vector<std::string> depends;
depends.push_back(origname);
diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx
index 34b6b330d..ba4266963 100644
--- a/Source/cmFileAPI.cxx
+++ b/Source/cmFileAPI.cxx
@@ -413,6 +413,14 @@ std::string cmFileAPI::ObjectName(Object const& o)
return name;
}
+Json::Value cmFileAPI::BuildVersion(unsigned int major, unsigned int minor)
+{
+ Json::Value version;
+ version["major"] = major;
+ version["minor"] = minor;
+ return version;
+}
+
Json::Value cmFileAPI::BuildObject(Object const& object)
{
Json::Value value;
@@ -680,10 +688,9 @@ Json::Value cmFileAPI::BuildCodeModel(Object const& object)
Json::Value codemodel = cmFileAPICodemodelDump(*this, object.Version);
codemodel["kind"] = this->ObjectKindName(object.Kind);
- Json::Value& version = codemodel["version"] = Json::objectValue;
+ Json::Value& version = codemodel["version"];
if (object.Version == 2) {
- version["major"] = 2;
- version["minor"] = CodeModelV2Minor;
+ version = BuildVersion(2, CodeModelV2Minor);
} else {
return codemodel; // should be unreachable
}
@@ -716,10 +723,9 @@ Json::Value cmFileAPI::BuildCache(Object const& object)
Json::Value cache = cmFileAPICacheDump(*this, object.Version);
cache["kind"] = this->ObjectKindName(object.Kind);
- Json::Value& version = cache["version"] = Json::objectValue;
+ Json::Value& version = cache["version"];
if (object.Version == 2) {
- version["major"] = 2;
- version["minor"] = CacheV2Minor;
+ version = BuildVersion(2, CacheV2Minor);
} else {
return cache; // should be unreachable
}
@@ -752,10 +758,9 @@ Json::Value cmFileAPI::BuildCMakeFiles(Object const& object)
Json::Value cmakeFiles = cmFileAPICMakeFilesDump(*this, object.Version);
cmakeFiles["kind"] = this->ObjectKindName(object.Kind);
- Json::Value& version = cmakeFiles["version"] = Json::objectValue;
+ Json::Value& version = cmakeFiles["version"];
if (object.Version == 1) {
- version["major"] = 1;
- version["minor"] = CMakeFilesV1Minor;
+ version = BuildVersion(1, CMakeFilesV1Minor);
} else {
return cmakeFiles; // should be unreachable
}
@@ -788,13 +793,43 @@ Json::Value cmFileAPI::BuildInternalTest(Object const& object)
{
Json::Value test = Json::objectValue;
test["kind"] = this->ObjectKindName(object.Kind);
- Json::Value& version = test["version"] = Json::objectValue;
+ Json::Value& version = test["version"];
if (object.Version == 2) {
- version["major"] = 2;
- version["minor"] = InternalTestV2Minor;
+ version = BuildVersion(2, InternalTestV2Minor);
} else {
- version["major"] = 1;
- version["minor"] = InternalTestV1Minor;
+ version = BuildVersion(1, InternalTestV1Minor);
}
return test;
}
+
+Json::Value cmFileAPI::ReportCapabilities()
+{
+ Json::Value capabilities = Json::objectValue;
+ Json::Value& requests = capabilities["requests"] = Json::arrayValue;
+
+ {
+ Json::Value request = Json::objectValue;
+ request["kind"] = ObjectKindName(ObjectKind::CodeModel);
+ Json::Value& versions = request["version"] = Json::arrayValue;
+ versions.append(BuildVersion(2, CodeModelV2Minor));
+ requests.append(std::move(request)); // NOLINT(*)
+ }
+
+ {
+ Json::Value request = Json::objectValue;
+ request["kind"] = ObjectKindName(ObjectKind::Cache);
+ Json::Value& versions = request["version"] = Json::arrayValue;
+ versions.append(BuildVersion(2, CacheV2Minor));
+ requests.append(std::move(request)); // NOLINT(*)
+ }
+
+ {
+ Json::Value request = Json::objectValue;
+ request["kind"] = ObjectKindName(ObjectKind::CMakeFiles);
+ Json::Value& versions = request["version"] = Json::arrayValue;
+ versions.append(BuildVersion(1, CMakeFilesV1Minor));
+ requests.append(std::move(request)); // NOLINT(*)
+ }
+
+ return capabilities;
+}
diff --git a/Source/cmFileAPI.h b/Source/cmFileAPI.h
index 341b072f4..602efa8ed 100644
--- a/Source/cmFileAPI.h
+++ b/Source/cmFileAPI.h
@@ -36,6 +36,9 @@ public:
and holding the original object. Other JSON types are unchanged. */
Json::Value MaybeJsonFile(Json::Value in, std::string const& prefix);
+ /** Report file-api capabilities for cmake -E capabilities. */
+ static Json::Value ReportCapabilities();
+
private:
cmake* CMakeInstance;
@@ -162,6 +165,8 @@ private:
static const char* ObjectKindName(ObjectKind kind);
static std::string ObjectName(Object const& o);
+ static Json::Value BuildVersion(unsigned int major, unsigned int minor);
+
Json::Value BuildObject(Object const& object);
ClientRequests BuildClientRequests(Json::Value const& requests);
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index 45e830318..0fb166af5 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmFileAPICodemodel.h"
+#include "cmAlgorithms.h"
#include "cmCryptoHash.h"
#include "cmFileAPI.h"
#include "cmGeneratorExpression.h"
@@ -477,8 +478,7 @@ Json::Value CodemodelConfig::DumpTargets()
cmGlobalGenerator* gg =
this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
for (cmLocalGenerator const* lg : gg->GetLocalGenerators()) {
- std::vector<cmGeneratorTarget*> const& list = lg->GetGeneratorTargets();
- targetList.insert(targetList.end(), list.begin(), list.end());
+ cmAppend(targetList, lg->GetGeneratorTargets());
}
std::sort(targetList.begin(), targetList.end(),
[](cmGeneratorTarget* l, cmGeneratorTarget* r) {
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 0f911c170..7a3954e4d 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -3,7 +3,7 @@
#include "cmFileCommand.h"
#include "cm_kwiml.h"
-#include "cmsys/Directory.hxx"
+#include "cm_static_string_view.hxx"
#include "cmsys/FStream.hxx"
#include "cmsys/Glob.hxx"
#include "cmsys/RegularExpression.hxx"
@@ -16,24 +16,24 @@
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <utility>
#include <vector>
#include "cmAlgorithms.h"
-#include "cmCommandArgumentsHelper.h"
+#include "cmArgumentParser.h"
#include "cmCryptoHash.h"
-#include "cmFSPermissions.h"
+#include "cmFileCopier.h"
+#include "cmFileInstaller.h"
#include "cmFileLockPool.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTimes.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
#include "cmHexFileConverter.h"
-#include "cmInstallType.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
#include "cmTimestamp.h"
#include "cm_sys_stat.h"
@@ -53,10 +53,6 @@
# include <windows.h>
#endif
-class cmSystemToolsFileTime;
-
-using namespace cmFSPermissions;
-
#if defined(_WIN32)
// libcurl doesn't support file:// urls for unicode filenames on Windows.
// Convert string from UTF-8 to ACP if this is a file:// URL.
@@ -223,7 +219,7 @@ bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
bool writable = false;
// Set permissions to writable
- if (cmSystemTools::GetPermissions(fileName.c_str(), mode)) {
+ if (cmSystemTools::GetPermissions(fileName, mode)) {
#if defined(_MSC_VER) || defined(__MINGW32__)
writable = (mode & S_IWRITE) != 0;
mode_t newMode = mode | S_IWRITE;
@@ -232,7 +228,7 @@ bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
mode_t newMode = mode | S_IWUSR | S_IWGRP;
#endif
if (!writable) {
- cmSystemTools::SetPermissions(fileName.c_str(), newMode);
+ cmSystemTools::SetPermissions(fileName, newMode);
}
}
// If GetPermissions fails, pretend like it is ok. File open will fail if
@@ -259,7 +255,7 @@ bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args,
}
file.close();
if (mode && !writable) {
- cmSystemTools::SetPermissions(fileName.c_str(), mode);
+ cmSystemTools::SetPermissions(fileName, mode);
}
return true;
}
@@ -272,36 +268,34 @@ bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args)
return false;
}
- cmCommandArgumentsHelper argHelper;
- cmCommandArgumentGroup group;
+ std::string const& fileNameArg = args[1];
+ std::string const& variable = args[2];
- cmCAString readArg(&argHelper, "READ");
- cmCAString fileNameArg(&argHelper, nullptr);
- cmCAString resultArg(&argHelper, nullptr);
+ struct Arguments
+ {
+ std::string Offset;
+ std::string Limit;
+ bool Hex = false;
+ };
- cmCAString offsetArg(&argHelper, "OFFSET", &group);
- cmCAString limitArg(&argHelper, "LIMIT", &group);
- cmCAEnabler hexOutputArg(&argHelper, "HEX", &group);
- readArg.Follows(nullptr);
- fileNameArg.Follows(&readArg);
- resultArg.Follows(&fileNameArg);
- group.Follows(&resultArg);
- argHelper.Parse(&args, nullptr);
+ static auto const parser = cmArgumentParser<Arguments>{}
+ .Bind("OFFSET"_s, &Arguments::Offset)
+ .Bind("LIMIT"_s, &Arguments::Limit)
+ .Bind("HEX"_s, &Arguments::Hex);
- std::string fileName = fileNameArg.GetString();
+ Arguments const arguments = parser.Parse(cmMakeRange(args).advance(3));
+
+ std::string fileName = fileNameArg;
if (!cmsys::SystemTools::FileIsFullPath(fileName)) {
fileName = this->Makefile->GetCurrentSourceDirectory();
- fileName += "/" + fileNameArg.GetString();
+ fileName += "/" + fileNameArg;
}
- std::string variable = resultArg.GetString();
-
// Open the specified file.
#if defined(_WIN32) || defined(__CYGWIN__)
- cmsys::ifstream file(
- fileName.c_str(),
- std::ios::in |
- (hexOutputArg.IsEnabled() ? std::ios::binary : std::ios::in));
+ cmsys::ifstream file(fileName.c_str(),
+ arguments.Hex ? (std::ios::binary | std::ios::in)
+ : std::ios::in);
#else
cmsys::ifstream file(fileName.c_str());
#endif
@@ -317,21 +311,21 @@ bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args)
// is there a limit?
long sizeLimit = -1;
- if (!limitArg.GetString().empty()) {
- sizeLimit = atoi(limitArg.GetCString());
+ if (!arguments.Limit.empty()) {
+ sizeLimit = atoi(arguments.Limit.c_str());
}
// is there an offset?
long offset = 0;
- if (!offsetArg.GetString().empty()) {
- offset = atoi(offsetArg.GetCString());
+ if (!arguments.Offset.empty()) {
+ offset = atoi(arguments.Offset.c_str());
}
file.seekg(offset, std::ios::beg); // explicit ios::beg for IBM VisualAge 6
std::string output;
- if (hexOutputArg.IsEnabled()) {
+ if (arguments.Hex) {
// Convert part of the file into hex code
char c;
while ((sizeLimit != 0) && (file.get(c))) {
@@ -393,7 +387,7 @@ bool cmFileCommand::HandleHashCommand(std::vector<std::string> const& args)
#else
std::ostringstream e;
e << args[0] << " not available during bootstrap";
- this->SetError(e.str().c_str());
+ this->SetError(e.str());
return false;
#endif
}
@@ -523,7 +517,7 @@ bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args)
maxlen = len;
arg_mode = arg_none;
} else if (arg_mode == arg_regex) {
- if (!regex.compile(args[i].c_str())) {
+ if (!regex.compile(args[i])) {
std::ostringstream e;
e << "STRINGS option REGEX value \"" << args[i]
<< "\" could not be compiled.";
@@ -563,8 +557,7 @@ bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args)
std::string binaryFileName = this->Makefile->GetCurrentBinaryDirectory();
binaryFileName += "/CMakeFiles";
binaryFileName += "/FileCommandStringsBinaryFile";
- if (cmHexFileConverter::TryConvert(fileName.c_str(),
- binaryFileName.c_str())) {
+ if (cmHexFileConverter::TryConvert(fileName, binaryFileName)) {
fileName = binaryFileName;
}
}
@@ -897,7 +890,7 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
}
std::vector<std::string>& foundFiles = g.GetFiles();
- files.insert(files.end(), foundFiles.begin(), foundFiles.end());
+ cmAppend(files, foundFiles);
if (configureDepends) {
std::sort(foundFiles.begin(), foundFiles.end());
@@ -947,16 +940,14 @@ bool cmFileCommand::HandleMakeDirectoryCommand(
// File command has at least one argument
assert(args.size() > 1);
- std::vector<std::string>::const_iterator i = args.begin();
-
- i++; // Get rid of subcommand
-
std::string expr;
- for (; i != args.end(); ++i) {
- const std::string* cdir = &(*i);
- if (!cmsys::SystemTools::FileIsFullPath(*i)) {
+ for (std::string const& arg :
+ cmMakeRange(args).advance(1)) // Get rid of subcommand
+ {
+ const std::string* cdir = &arg;
+ if (!cmsys::SystemTools::FileIsFullPath(arg)) {
expr = this->Makefile->GetCurrentSourceDirectory();
- expr += "/" + *i;
+ expr += "/" + arg;
cdir = &expr;
}
if (!this->Makefile->CanIWriteThisFile(*cdir)) {
@@ -981,15 +972,13 @@ bool cmFileCommand::HandleTouchCommand(std::vector<std::string> const& args,
// File command has at least one argument
assert(args.size() > 1);
- std::vector<std::string>::const_iterator i = args.begin();
-
- i++; // Get rid of subcommand
-
- for (; i != args.end(); ++i) {
- std::string tfile = *i;
+ for (std::string const& arg :
+ cmMakeRange(args).advance(1)) // Get rid of subcommand
+ {
+ std::string tfile = arg;
if (!cmsys::SystemTools::FileIsFullPath(tfile)) {
tfile = this->Makefile->GetCurrentSourceDirectory();
- tfile += "/" + *i;
+ tfile += "/" + arg;
}
if (!this->Makefile->CanIWriteThisFile(tfile)) {
std::string e =
@@ -1061,1088 +1050,17 @@ bool cmFileCommand::HandleDifferentCommand(
return true;
}
-// File installation helper class.
-struct cmFileCopier
-{
- cmFileCopier(cmFileCommand* command, const char* name = "COPY")
- : FileCommand(command)
- , Makefile(command->GetMakefile())
- , Name(name)
- , Always(false)
- , MatchlessFiles(true)
- , FilePermissions(0)
- , DirPermissions(0)
- , CurrentMatchRule(nullptr)
- , UseGivenPermissionsFile(false)
- , UseGivenPermissionsDir(false)
- , UseSourcePermissions(true)
- , Doing(DoingNone)
- {
- }
- virtual ~cmFileCopier() = default;
-
- bool Run(std::vector<std::string> const& args);
-
-protected:
- cmFileCommand* FileCommand;
- cmMakefile* Makefile;
- const char* Name;
- bool Always;
- cmFileTimeComparison FileTimes;
-
- // Whether to install a file not matching any expression.
- bool MatchlessFiles;
-
- // Permissions for files and directories installed by this object.
- mode_t FilePermissions;
- mode_t DirPermissions;
-
- // Properties set by pattern and regex match rules.
- struct MatchProperties
- {
- bool Exclude = false;
- mode_t Permissions = 0;
- };
- struct MatchRule
- {
- cmsys::RegularExpression Regex;
- MatchProperties Properties;
- std::string RegexString;
- MatchRule(std::string const& regex)
- : Regex(regex.c_str())
- , RegexString(regex)
- {
- }
- };
- std::vector<MatchRule> MatchRules;
-
- // Get the properties from rules matching this input file.
- MatchProperties CollectMatchProperties(const char* file)
- {
-// Match rules are case-insensitive on some platforms.
-#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
- std::string lower = cmSystemTools::LowerCase(file);
- const char* file_to_match = lower.c_str();
-#else
- const char* file_to_match = file;
-#endif
-
- // Collect properties from all matching rules.
- bool matched = false;
- MatchProperties result;
- for (MatchRule& mr : this->MatchRules) {
- if (mr.Regex.find(file_to_match)) {
- matched = true;
- result.Exclude |= mr.Properties.Exclude;
- result.Permissions |= mr.Properties.Permissions;
- }
- }
- if (!matched && !this->MatchlessFiles) {
- result.Exclude = !cmSystemTools::FileIsDirectory(file);
- }
- return result;
- }
-
- bool SetPermissions(const char* toFile, mode_t permissions)
- {
- if (permissions) {
-#ifdef WIN32
- if (Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
- // Store the mode in an NTFS alternate stream.
- std::string mode_t_adt_filename =
- std::string(toFile) + ":cmake_mode_t";
-
- // Writing to an NTFS alternate stream changes the modification
- // time, so we need to save and restore its original value.
- cmSystemToolsFileTime* file_time_orig = cmSystemTools::FileTimeNew();
- cmSystemTools::FileTimeGet(toFile, file_time_orig);
-
- cmsys::ofstream permissionStream(mode_t_adt_filename.c_str());
-
- if (permissionStream) {
- permissionStream << std::oct << permissions << std::endl;
- }
-
- permissionStream.close();
-
- cmSystemTools::FileTimeSet(toFile, file_time_orig);
-
- cmSystemTools::FileTimeDelete(file_time_orig);
- }
-#endif
-
- if (!cmSystemTools::SetPermissions(toFile, permissions)) {
- std::ostringstream e;
- e << this->Name << " cannot set permissions on \"" << toFile << "\"";
- this->FileCommand->SetError(e.str());
- return false;
- }
- }
- return true;
- }
-
- // Translate an argument to a permissions bit.
- bool CheckPermissions(std::string const& arg, mode_t& permissions)
- {
- if (!cmFSPermissions::stringToModeT(arg, permissions)) {
- std::ostringstream e;
- e << this->Name << " given invalid permission \"" << arg << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
- return true;
- }
-
- bool InstallSymlink(const char* fromFile, const char* toFile);
- bool InstallFile(const char* fromFile, const char* toFile,
- MatchProperties match_properties);
- bool InstallDirectory(const char* source, const char* destination,
- MatchProperties match_properties);
- virtual bool Install(const char* fromFile, const char* toFile);
- virtual std::string const& ToName(std::string const& fromName)
- {
- return fromName;
- }
-
- enum Type
- {
- TypeFile,
- TypeDir,
- TypeLink
- };
- virtual void ReportCopy(const char*, Type, bool) {}
- virtual bool ReportMissing(const char* fromFile)
- {
- // The input file does not exist and installation is not optional.
- std::ostringstream e;
- e << this->Name << " cannot find \"" << fromFile << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- MatchRule* CurrentMatchRule;
- bool UseGivenPermissionsFile;
- bool UseGivenPermissionsDir;
- bool UseSourcePermissions;
- std::string Destination;
- std::string FilesFromDir;
- std::vector<std::string> Files;
- int Doing;
-
- virtual bool Parse(std::vector<std::string> const& args);
- enum
- {
- DoingNone,
- DoingError,
- DoingDestination,
- DoingFilesFromDir,
- DoingFiles,
- DoingPattern,
- DoingRegex,
- DoingPermissionsFile,
- DoingPermissionsDir,
- DoingPermissionsMatch,
- DoingLast1
- };
- virtual bool CheckKeyword(std::string const& arg);
- virtual bool CheckValue(std::string const& arg);
-
- void NotBeforeMatch(std::string const& arg)
- {
- std::ostringstream e;
- e << "option " << arg << " may not appear before PATTERN or REGEX.";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- }
- void NotAfterMatch(std::string const& arg)
- {
- std::ostringstream e;
- e << "option " << arg << " may not appear after PATTERN or REGEX.";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- }
- virtual void DefaultFilePermissions()
- {
- // Use read/write permissions.
- this->FilePermissions = 0;
- this->FilePermissions |= mode_owner_read;
- this->FilePermissions |= mode_owner_write;
- this->FilePermissions |= mode_group_read;
- this->FilePermissions |= mode_world_read;
- }
- virtual void DefaultDirectoryPermissions()
- {
- // Use read/write/executable permissions.
- this->DirPermissions = 0;
- this->DirPermissions |= mode_owner_read;
- this->DirPermissions |= mode_owner_write;
- this->DirPermissions |= mode_owner_execute;
- this->DirPermissions |= mode_group_read;
- this->DirPermissions |= mode_group_execute;
- this->DirPermissions |= mode_world_read;
- this->DirPermissions |= mode_world_execute;
- }
-
- bool GetDefaultDirectoryPermissions(mode_t** mode)
- {
- // check if default dir creation permissions were set
- const char* default_dir_install_permissions =
- this->Makefile->GetDefinition(
- "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
- if (default_dir_install_permissions && *default_dir_install_permissions) {
- std::vector<std::string> items;
- cmSystemTools::ExpandListArgument(default_dir_install_permissions,
- items);
- for (const auto& arg : items) {
- if (!this->CheckPermissions(arg, **mode)) {
- std::ostringstream e;
- e << this->FileCommand->GetError()
- << " Set with CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS "
- "variable.";
- this->FileCommand->SetError(e.str());
- return false;
- }
- }
- } else {
- *mode = nullptr;
- }
-
- return true;
- }
-};
-
-bool cmFileCopier::Parse(std::vector<std::string> const& args)
-{
- this->Doing = DoingFiles;
- for (unsigned int i = 1; i < args.size(); ++i) {
- // Check this argument.
- if (!this->CheckKeyword(args[i]) && !this->CheckValue(args[i])) {
- std::ostringstream e;
- e << "called with unknown argument \"" << args[i] << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Quit if an argument is invalid.
- if (this->Doing == DoingError) {
- return false;
- }
- }
-
- // Require a destination.
- if (this->Destination.empty()) {
- std::ostringstream e;
- e << this->Name << " given no DESTINATION";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // If file permissions were not specified set default permissions.
- if (!this->UseGivenPermissionsFile && !this->UseSourcePermissions) {
- this->DefaultFilePermissions();
- }
-
- // If directory permissions were not specified set default permissions.
- if (!this->UseGivenPermissionsDir && !this->UseSourcePermissions) {
- this->DefaultDirectoryPermissions();
- }
-
- return true;
-}
-
-bool cmFileCopier::CheckKeyword(std::string const& arg)
-{
- if (arg == "DESTINATION") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingDestination;
- }
- } else if (arg == "FILES_FROM_DIR") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingFilesFromDir;
- }
- } else if (arg == "PATTERN") {
- this->Doing = DoingPattern;
- } else if (arg == "REGEX") {
- this->Doing = DoingRegex;
- } else if (arg == "EXCLUDE") {
- // Add this property to the current match rule.
- if (this->CurrentMatchRule) {
- this->CurrentMatchRule->Properties.Exclude = true;
- this->Doing = DoingNone;
- } else {
- this->NotBeforeMatch(arg);
- }
- } else if (arg == "PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->Doing = DoingPermissionsMatch;
- } else {
- this->NotBeforeMatch(arg);
- }
- } else if (arg == "FILE_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingPermissionsFile;
- this->UseGivenPermissionsFile = true;
- }
- } else if (arg == "DIRECTORY_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingPermissionsDir;
- this->UseGivenPermissionsDir = true;
- }
- } else if (arg == "USE_SOURCE_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->UseSourcePermissions = true;
- }
- } else if (arg == "NO_SOURCE_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->UseSourcePermissions = false;
- }
- } else if (arg == "FILES_MATCHING") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->MatchlessFiles = false;
- }
- } else {
- return false;
- }
- return true;
-}
-
-bool cmFileCopier::CheckValue(std::string const& arg)
-{
- switch (this->Doing) {
- case DoingFiles:
- this->Files.push_back(arg);
- break;
- case DoingDestination:
- if (arg.empty() || cmSystemTools::FileIsFullPath(arg)) {
- this->Destination = arg;
- } else {
- this->Destination = this->Makefile->GetCurrentBinaryDirectory();
- this->Destination += "/" + arg;
- }
- this->Doing = DoingNone;
- break;
- case DoingFilesFromDir:
- if (cmSystemTools::FileIsFullPath(arg)) {
- this->FilesFromDir = arg;
- } else {
- this->FilesFromDir = this->Makefile->GetCurrentSourceDirectory();
- this->FilesFromDir += "/" + arg;
- }
- cmSystemTools::ConvertToUnixSlashes(this->FilesFromDir);
- this->Doing = DoingNone;
- break;
- case DoingPattern: {
- // Convert the pattern to a regular expression. Require a
- // leading slash and trailing end-of-string in the matched
- // string to make sure the pattern matches only whole file
- // names.
- std::string regex = "/";
- regex += cmsys::Glob::PatternToRegex(arg, false);
- regex += "$";
- this->MatchRules.emplace_back(regex);
- this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
- if (this->CurrentMatchRule->Regex.is_valid()) {
- this->Doing = DoingNone;
- } else {
- std::ostringstream e;
- e << "could not compile PATTERN \"" << arg << "\".";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- }
- } break;
- case DoingRegex:
- this->MatchRules.emplace_back(arg);
- this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
- if (this->CurrentMatchRule->Regex.is_valid()) {
- this->Doing = DoingNone;
- } else {
- std::ostringstream e;
- e << "could not compile REGEX \"" << arg << "\".";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- }
- break;
- case DoingPermissionsFile:
- if (!this->CheckPermissions(arg, this->FilePermissions)) {
- this->Doing = DoingError;
- }
- break;
- case DoingPermissionsDir:
- if (!this->CheckPermissions(arg, this->DirPermissions)) {
- this->Doing = DoingError;
- }
- break;
- case DoingPermissionsMatch:
- if (!this->CheckPermissions(
- arg, this->CurrentMatchRule->Properties.Permissions)) {
- this->Doing = DoingError;
- }
- break;
- default:
- return false;
- }
- return true;
-}
-
-bool cmFileCopier::Run(std::vector<std::string> const& args)
-{
- if (!this->Parse(args)) {
- return false;
- }
-
- for (std::string const& f : this->Files) {
- std::string file;
- if (!f.empty() && !cmSystemTools::FileIsFullPath(f)) {
- if (!this->FilesFromDir.empty()) {
- file = this->FilesFromDir;
- } else {
- file = this->Makefile->GetCurrentSourceDirectory();
- }
- file += "/";
- file += f;
- } else if (!this->FilesFromDir.empty()) {
- this->FileCommand->SetError("option FILES_FROM_DIR requires all files "
- "to be specified as relative paths.");
- return false;
- } else {
- file = f;
- }
-
- // Split the input file into its directory and name components.
- std::vector<std::string> fromPathComponents;
- cmSystemTools::SplitPath(file, fromPathComponents);
- std::string fromName = *(fromPathComponents.end() - 1);
- std::string fromDir = cmSystemTools::JoinPath(
- fromPathComponents.begin(), fromPathComponents.end() - 1);
-
- // Compute the full path to the destination file.
- std::string toFile = this->Destination;
- if (!this->FilesFromDir.empty()) {
- std::string dir = cmSystemTools::GetFilenamePath(f);
- if (!dir.empty()) {
- toFile += "/";
- toFile += dir;
- }
- }
- std::string const& toName = this->ToName(fromName);
- if (!toName.empty()) {
- toFile += "/";
- toFile += toName;
- }
-
- // Construct the full path to the source file. The file name may
- // have been changed above.
- std::string fromFile = fromDir;
- if (!fromName.empty()) {
- fromFile += "/";
- fromFile += fromName;
- }
-
- if (!this->Install(fromFile.c_str(), toFile.c_str())) {
- return false;
- }
- }
- return true;
-}
-
-bool cmFileCopier::Install(const char* fromFile, const char* toFile)
-{
- if (!*fromFile) {
- std::ostringstream e;
- e << "INSTALL encountered an empty string input file name.";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Collect any properties matching this file name.
- MatchProperties match_properties = this->CollectMatchProperties(fromFile);
-
- // Skip the file if it is excluded.
- if (match_properties.Exclude) {
- return true;
- }
-
- if (cmSystemTools::SameFile(fromFile, toFile)) {
- return true;
- }
- if (cmSystemTools::FileIsSymlink(fromFile)) {
- return this->InstallSymlink(fromFile, toFile);
- }
- if (cmSystemTools::FileIsDirectory(fromFile)) {
- return this->InstallDirectory(fromFile, toFile, match_properties);
- }
- if (cmSystemTools::FileExists(fromFile)) {
- return this->InstallFile(fromFile, toFile, match_properties);
- }
- return this->ReportMissing(fromFile);
-}
-
-bool cmFileCopier::InstallSymlink(const char* fromFile, const char* toFile)
-{
- // Read the original symlink.
- std::string symlinkTarget;
- if (!cmSystemTools::ReadSymlink(fromFile, symlinkTarget)) {
- std::ostringstream e;
- e << this->Name << " cannot read symlink \"" << fromFile
- << "\" to duplicate at \"" << toFile << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Compare the symlink value to that at the destination if not
- // always installing.
- bool copy = true;
- if (!this->Always) {
- std::string oldSymlinkTarget;
- if (cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget)) {
- if (symlinkTarget == oldSymlinkTarget) {
- copy = false;
- }
- }
- }
-
- // Inform the user about this file installation.
- this->ReportCopy(toFile, TypeLink, copy);
-
- if (copy) {
- // Remove the destination file so we can always create the symlink.
- cmSystemTools::RemoveFile(toFile);
-
- // Create destination directory if it doesn't exist
- cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(toFile));
-
- // Create the symlink.
- if (!cmSystemTools::CreateSymlink(symlinkTarget, toFile)) {
- std::ostringstream e;
- e << this->Name << " cannot duplicate symlink \"" << fromFile
- << "\" at \"" << toFile << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
- }
-
- return true;
-}
-
-bool cmFileCopier::InstallFile(const char* fromFile, const char* toFile,
- MatchProperties match_properties)
-{
- // Determine whether we will copy the file.
- bool copy = true;
- if (!this->Always) {
- // If both files exist with the same time do not copy.
- if (!this->FileTimes.FileTimesDiffer(fromFile, toFile)) {
- copy = false;
- }
- }
-
- // Inform the user about this file installation.
- this->ReportCopy(toFile, TypeFile, copy);
-
- // Copy the file.
- if (copy && !cmSystemTools::CopyAFile(fromFile, toFile, true)) {
- std::ostringstream e;
- e << this->Name << " cannot copy file \"" << fromFile << "\" to \""
- << toFile << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Set the file modification time of the destination file.
- if (copy && !this->Always) {
- // Add write permission so we can set the file time.
- // Permissions are set unconditionally below anyway.
- mode_t perm = 0;
- if (cmSystemTools::GetPermissions(toFile, perm)) {
- cmSystemTools::SetPermissions(toFile, perm | mode_owner_write);
- }
- if (!cmSystemTools::CopyFileTime(fromFile, toFile)) {
- std::ostringstream e;
- e << this->Name << " cannot set modification time on \"" << toFile
- << "\"";
- this->FileCommand->SetError(e.str());
- return false;
- }
- }
-
- // Set permissions of the destination file.
- mode_t permissions =
- (match_properties.Permissions ? match_properties.Permissions
- : this->FilePermissions);
- if (!permissions) {
- // No permissions were explicitly provided but the user requested
- // that the source file permissions be used.
- cmSystemTools::GetPermissions(fromFile, permissions);
- }
- return this->SetPermissions(toFile, permissions);
-}
-
-bool cmFileCopier::InstallDirectory(const char* source,
- const char* destination,
- MatchProperties match_properties)
-{
- // Inform the user about this directory installation.
- this->ReportCopy(destination, TypeDir,
- !cmSystemTools::FileIsDirectory(destination));
-
- // check if default dir creation permissions were set
- mode_t default_dir_mode_v = 0;
- mode_t* default_dir_mode = &default_dir_mode_v;
- if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
- return false;
- }
-
- // Make sure the destination directory exists.
- if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
- std::ostringstream e;
- e << this->Name << " cannot make directory \"" << destination
- << "\": " << cmSystemTools::GetLastSystemError();
- this->FileCommand->SetError(e.str());
- return false;
- }
-
- // Compute the requested permissions for the destination directory.
- mode_t permissions =
- (match_properties.Permissions ? match_properties.Permissions
- : this->DirPermissions);
- if (!permissions) {
- // No permissions were explicitly provided but the user requested
- // that the source directory permissions be used.
- cmSystemTools::GetPermissions(source, permissions);
- }
-
- // Compute the set of permissions required on this directory to
- // recursively install files and subdirectories safely.
- mode_t required_permissions =
- mode_owner_read | mode_owner_write | mode_owner_execute;
-
- // If the required permissions are specified it is safe to set the
- // final permissions now. Otherwise we must add the required
- // permissions temporarily during file installation.
- mode_t permissions_before = 0;
- mode_t permissions_after = 0;
- if ((permissions & required_permissions) == required_permissions) {
- permissions_before = permissions;
- } else {
- permissions_before = permissions | required_permissions;
- permissions_after = permissions;
- }
-
- // Set the required permissions of the destination directory.
- if (!this->SetPermissions(destination, permissions_before)) {
- return false;
- }
-
- // Load the directory contents to traverse it recursively.
- cmsys::Directory dir;
- if (source && *source) {
- dir.Load(source);
- }
- unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
- for (unsigned long fileNum = 0; fileNum < numFiles; ++fileNum) {
- if (!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
- strcmp(dir.GetFile(fileNum), "..") == 0)) {
- std::string fromPath = source;
- fromPath += "/";
- fromPath += dir.GetFile(fileNum);
- std::string toPath = destination;
- toPath += "/";
- toPath += dir.GetFile(fileNum);
- if (!this->Install(fromPath.c_str(), toPath.c_str())) {
- return false;
- }
- }
- }
-
- // Set the requested permissions of the destination directory.
- return this->SetPermissions(destination, permissions_after);
-}
-
bool cmFileCommand::HandleCopyCommand(std::vector<std::string> const& args)
{
cmFileCopier copier(this);
return copier.Run(args);
}
-struct cmFileInstaller : public cmFileCopier
-{
- cmFileInstaller(cmFileCommand* command)
- : cmFileCopier(command, "INSTALL")
- , InstallType(cmInstallType_FILES)
- , Optional(false)
- , MessageAlways(false)
- , MessageLazy(false)
- , MessageNever(false)
- , DestDirLength(0)
- {
- // Installation does not use source permissions by default.
- this->UseSourcePermissions = false;
- // Check whether to copy files always or only if they have changed.
- std::string install_always;
- if (cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS", install_always)) {
- this->Always = cmSystemTools::IsOn(install_always);
- }
- // Get the current manifest.
- this->Manifest =
- this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
- }
- ~cmFileInstaller() override
- {
- // Save the updated install manifest.
- this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
- this->Manifest.c_str());
- }
-
-protected:
- cmInstallType InstallType;
- bool Optional;
- bool MessageAlways;
- bool MessageLazy;
- bool MessageNever;
- int DestDirLength;
- std::string Rename;
-
- std::string Manifest;
- void ManifestAppend(std::string const& file)
- {
- if (!this->Manifest.empty()) {
- this->Manifest += ";";
- }
- this->Manifest += file.substr(this->DestDirLength);
- }
-
- std::string const& ToName(std::string const& fromName) override
- {
- return this->Rename.empty() ? fromName : this->Rename;
- }
-
- void ReportCopy(const char* toFile, Type type, bool copy) override
- {
- if (!this->MessageNever && (copy || !this->MessageLazy)) {
- std::string message = (copy ? "Installing: " : "Up-to-date: ");
- message += toFile;
- this->Makefile->DisplayStatus(message.c_str(), -1);
- }
- if (type != TypeDir) {
- // Add the file to the manifest.
- this->ManifestAppend(toFile);
- }
- }
- bool ReportMissing(const char* fromFile) override
- {
- return (this->Optional || this->cmFileCopier::ReportMissing(fromFile));
- }
- bool Install(const char* fromFile, const char* toFile) override
- {
- // Support installing from empty source to make a directory.
- if (this->InstallType == cmInstallType_DIRECTORY && !*fromFile) {
- return this->InstallDirectory(fromFile, toFile, MatchProperties());
- }
- return this->cmFileCopier::Install(fromFile, toFile);
- }
-
- bool Parse(std::vector<std::string> const& args) override;
- enum
- {
- DoingType = DoingLast1,
- DoingRename,
- DoingLast2
- };
- bool CheckKeyword(std::string const& arg) override;
- bool CheckValue(std::string const& arg) override;
- void DefaultFilePermissions() override
- {
- this->cmFileCopier::DefaultFilePermissions();
- // Add execute permissions based on the target type.
- switch (this->InstallType) {
- case cmInstallType_SHARED_LIBRARY:
- case cmInstallType_MODULE_LIBRARY:
- if (this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE")) {
- break;
- }
- CM_FALLTHROUGH;
- case cmInstallType_EXECUTABLE:
- case cmInstallType_PROGRAMS:
- this->FilePermissions |= mode_owner_execute;
- this->FilePermissions |= mode_group_execute;
- this->FilePermissions |= mode_world_execute;
- break;
- default:
- break;
- }
- }
- bool GetTargetTypeFromString(const std::string& stype);
- bool HandleInstallDestination();
-};
-
-bool cmFileInstaller::Parse(std::vector<std::string> const& args)
-{
- if (!this->cmFileCopier::Parse(args)) {
- return false;
- }
-
- if (!this->Rename.empty()) {
- if (!this->FilesFromDir.empty()) {
- this->FileCommand->SetError("INSTALL option RENAME may not be "
- "combined with FILES_FROM_DIR.");
- return false;
- }
- if (this->InstallType != cmInstallType_FILES &&
- this->InstallType != cmInstallType_PROGRAMS) {
- this->FileCommand->SetError("INSTALL option RENAME may be used "
- "only with FILES or PROGRAMS.");
- return false;
- }
- if (this->Files.size() > 1) {
- this->FileCommand->SetError("INSTALL option RENAME may be used "
- "only with one file.");
- return false;
- }
- }
-
- if (!this->HandleInstallDestination()) {
- return false;
- }
-
- if (((this->MessageAlways ? 1 : 0) + (this->MessageLazy ? 1 : 0) +
- (this->MessageNever ? 1 : 0)) > 1) {
- this->FileCommand->SetError("INSTALL options MESSAGE_ALWAYS, "
- "MESSAGE_LAZY, and MESSAGE_NEVER "
- "are mutually exclusive.");
- return false;
- }
-
- return true;
-}
-
-bool cmFileInstaller::CheckKeyword(std::string const& arg)
-{
- if (arg == "TYPE") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingType;
- }
- } else if (arg == "FILES") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingFiles;
- }
- } else if (arg == "RENAME") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingRename;
- }
- } else if (arg == "OPTIONAL") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->Optional = true;
- }
- } else if (arg == "MESSAGE_ALWAYS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->MessageAlways = true;
- }
- } else if (arg == "MESSAGE_LAZY") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->MessageLazy = true;
- }
- } else if (arg == "MESSAGE_NEVER") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- this->Doing = DoingNone;
- this->MessageNever = true;
- }
- } else if (arg == "PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->Doing = DoingPermissionsMatch;
- } else {
- // file(INSTALL) aliases PERMISSIONS to FILE_PERMISSIONS
- this->Doing = DoingPermissionsFile;
- this->UseGivenPermissionsFile = true;
- }
- } else if (arg == "DIR_PERMISSIONS") {
- if (this->CurrentMatchRule) {
- this->NotAfterMatch(arg);
- } else {
- // file(INSTALL) aliases DIR_PERMISSIONS to DIRECTORY_PERMISSIONS
- this->Doing = DoingPermissionsDir;
- this->UseGivenPermissionsDir = true;
- }
- } else if (arg == "COMPONENTS" || arg == "CONFIGURATIONS" ||
- arg == "PROPERTIES") {
- std::ostringstream e;
- e << "INSTALL called with old-style " << arg << " argument. "
- << "This script was generated with an older version of CMake. "
- << "Re-run this cmake version on your build tree.";
- this->FileCommand->SetError(e.str());
- this->Doing = DoingError;
- } else {
- return this->cmFileCopier::CheckKeyword(arg);
- }
- return true;
-}
-
-bool cmFileInstaller::CheckValue(std::string const& arg)
-{
- switch (this->Doing) {
- case DoingType:
- if (!this->GetTargetTypeFromString(arg)) {
- this->Doing = DoingError;
- }
- break;
- case DoingRename:
- this->Rename = arg;
- break;
- default:
- return this->cmFileCopier::CheckValue(arg);
- }
- return true;
-}
-
-bool cmFileInstaller::GetTargetTypeFromString(const std::string& stype)
-{
- if (stype == "EXECUTABLE") {
- this->InstallType = cmInstallType_EXECUTABLE;
- } else if (stype == "FILE") {
- this->InstallType = cmInstallType_FILES;
- } else if (stype == "PROGRAM") {
- this->InstallType = cmInstallType_PROGRAMS;
- } else if (stype == "STATIC_LIBRARY") {
- this->InstallType = cmInstallType_STATIC_LIBRARY;
- } else if (stype == "SHARED_LIBRARY") {
- this->InstallType = cmInstallType_SHARED_LIBRARY;
- } else if (stype == "MODULE") {
- this->InstallType = cmInstallType_MODULE_LIBRARY;
- } else if (stype == "DIRECTORY") {
- this->InstallType = cmInstallType_DIRECTORY;
- } else {
- std::ostringstream e;
- e << "Option TYPE given unknown value \"" << stype << "\".";
- this->FileCommand->SetError(e.str());
- return false;
- }
- return true;
-}
-
-bool cmFileInstaller::HandleInstallDestination()
-{
- std::string& destination = this->Destination;
-
- // allow for / to be a valid destination
- if (destination.size() < 2 && destination != "/") {
- this->FileCommand->SetError("called with inappropriate arguments. "
- "No DESTINATION provided or .");
- return false;
- }
-
- std::string sdestdir;
- if (cmSystemTools::GetEnv("DESTDIR", sdestdir) && !sdestdir.empty()) {
- cmSystemTools::ConvertToUnixSlashes(sdestdir);
- char ch1 = destination[0];
- char ch2 = destination[1];
- char ch3 = 0;
- if (destination.size() > 2) {
- ch3 = destination[2];
- }
- int skip = 0;
- if (ch1 != '/') {
- int relative = 0;
- if (((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z')) &&
- ch2 == ':') {
- // Assume windows
- // let's do some destdir magic:
- skip = 2;
- if (ch3 != '/') {
- relative = 1;
- }
- } else {
- relative = 1;
- }
- if (relative) {
- // This is relative path on unix or windows. Since we are doing
- // destdir, this case does not make sense.
- this->FileCommand->SetError(
- "called with relative DESTINATION. This "
- "does not make sense when using DESTDIR. Specify "
- "absolute path or remove DESTDIR environment variable.");
- return false;
- }
- } else {
- if (ch2 == '/') {
- // looks like a network path.
- std::string message =
- "called with network path DESTINATION. This "
- "does not make sense when using DESTDIR. Specify local "
- "absolute path or remove DESTDIR environment variable."
- "\nDESTINATION=\n";
- message += destination;
- this->FileCommand->SetError(message);
- return false;
- }
- }
- destination = sdestdir + (destination.c_str() + skip);
- this->DestDirLength = int(sdestdir.size());
- }
-
- // check if default dir creation permissions were set
- mode_t default_dir_mode_v = 0;
- mode_t* default_dir_mode = &default_dir_mode_v;
- if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
- return false;
- }
-
- if (this->InstallType != cmInstallType_DIRECTORY) {
- if (!cmSystemTools::FileExists(destination)) {
- if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
- std::string errstring = "cannot create directory: " + destination +
- ". Maybe need administrative privileges.";
- this->FileCommand->SetError(errstring);
- return false;
- }
- }
- if (!cmSystemTools::FileIsDirectory(destination)) {
- std::string errstring =
- "INSTALL destination: " + destination + " is not a directory.";
- this->FileCommand->SetError(errstring);
- return false;
- }
- }
- return true;
-}
-
bool cmFileCommand::HandleRPathChangeCommand(
std::vector<std::string> const& args)
{
// Evaluate arguments.
- const char* file = nullptr;
+ std::string file;
const char* oldRPath = nullptr;
const char* newRPath = nullptr;
enum Doing
@@ -2161,7 +1079,7 @@ bool cmFileCommand::HandleRPathChangeCommand(
} else if (args[i] == "FILE") {
doing = DoingFile;
} else if (doing == DoingFile) {
- file = args[i].c_str();
+ file = args[i];
doing = DoingNone;
} else if (doing == DoingOld) {
oldRPath = args[i].c_str();
@@ -2176,7 +1094,7 @@ bool cmFileCommand::HandleRPathChangeCommand(
return false;
}
}
- if (!file) {
+ if (file.empty()) {
this->SetError("RPATH_CHANGE not given FILE option.");
return false;
}
@@ -2195,8 +1113,7 @@ bool cmFileCommand::HandleRPathChangeCommand(
return false;
}
bool success = true;
- cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
- bool have_ft = cmSystemTools::FileTimeGet(file, ft);
+ cmFileTimes const ft(file);
std::string emsg;
bool changed;
if (!cmSystemTools::ChangeRPath(file, oldRPath, newRPath, &emsg, &changed)) {
@@ -2218,13 +1135,10 @@ bool cmFileCommand::HandleRPathChangeCommand(
message += "\" to \"";
message += newRPath;
message += "\"";
- this->Makefile->DisplayStatus(message.c_str(), -1);
- }
- if (have_ft) {
- cmSystemTools::FileTimeSet(file, ft);
+ this->Makefile->DisplayStatus(message, -1);
}
+ ft.Store(file);
}
- cmSystemTools::FileTimeDelete(ft);
return success;
}
@@ -2232,7 +1146,7 @@ bool cmFileCommand::HandleRPathRemoveCommand(
std::vector<std::string> const& args)
{
// Evaluate arguments.
- const char* file = nullptr;
+ std::string file;
enum Doing
{
DoingNone,
@@ -2243,7 +1157,7 @@ bool cmFileCommand::HandleRPathRemoveCommand(
if (args[i] == "FILE") {
doing = DoingFile;
} else if (doing == DoingFile) {
- file = args[i].c_str();
+ file = args[i];
doing = DoingNone;
} else {
std::ostringstream e;
@@ -2252,7 +1166,7 @@ bool cmFileCommand::HandleRPathRemoveCommand(
return false;
}
}
- if (!file) {
+ if (file.empty()) {
this->SetError("RPATH_REMOVE not given FILE option.");
return false;
}
@@ -2263,8 +1177,7 @@ bool cmFileCommand::HandleRPathRemoveCommand(
return false;
}
bool success = true;
- cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
- bool have_ft = cmSystemTools::FileTimeGet(file, ft);
+ cmFileTimes const ft(file);
std::string emsg;
bool removed;
if (!cmSystemTools::RemoveRPath(file, &emsg, &removed)) {
@@ -2282,13 +1195,10 @@ bool cmFileCommand::HandleRPathRemoveCommand(
std::string message = "Removed runtime path from \"";
message += file;
message += "\"";
- this->Makefile->DisplayStatus(message.c_str(), -1);
- }
- if (have_ft) {
- cmSystemTools::FileTimeSet(file, ft);
+ this->Makefile->DisplayStatus(message, -1);
}
+ ft.Store(file);
}
- cmSystemTools::FileTimeDelete(ft);
return success;
}
@@ -2296,7 +1206,7 @@ bool cmFileCommand::HandleRPathCheckCommand(
std::vector<std::string> const& args)
{
// Evaluate arguments.
- const char* file = nullptr;
+ std::string file;
const char* rpath = nullptr;
enum Doing
{
@@ -2311,7 +1221,7 @@ bool cmFileCommand::HandleRPathCheckCommand(
} else if (args[i] == "FILE") {
doing = DoingFile;
} else if (doing == DoingFile) {
- file = args[i].c_str();
+ file = args[i];
doing = DoingNone;
} else if (doing == DoingRPath) {
rpath = args[i].c_str();
@@ -2323,7 +1233,7 @@ bool cmFileCommand::HandleRPathCheckCommand(
return false;
}
}
- if (!file) {
+ if (file.empty()) {
this->SetError("RPATH_CHECK not given FILE option.");
return false;
}
@@ -2351,55 +1261,54 @@ bool cmFileCommand::HandleReadElfCommand(std::vector<std::string> const& args)
return false;
}
- cmCommandArgumentsHelper argHelper;
- cmCommandArgumentGroup group;
-
- cmCAString readArg(&argHelper, "READ_ELF");
- cmCAString fileNameArg(&argHelper, nullptr);
+ std::string const& fileNameArg = args[1];
- cmCAString rpathArg(&argHelper, "RPATH", &group);
- cmCAString runpathArg(&argHelper, "RUNPATH", &group);
- cmCAString errorArg(&argHelper, "CAPTURE_ERROR", &group);
+ struct Arguments
+ {
+ std::string RPath;
+ std::string RunPath;
+ std::string Error;
+ };
- readArg.Follows(nullptr);
- fileNameArg.Follows(&readArg);
- group.Follows(&fileNameArg);
- argHelper.Parse(&args, nullptr);
+ static auto const parser = cmArgumentParser<Arguments>{}
+ .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));
- if (!cmSystemTools::FileExists(fileNameArg.GetString(), true)) {
+ if (!cmSystemTools::FileExists(fileNameArg, true)) {
std::ostringstream e;
- e << "READ_ELF given FILE \"" << fileNameArg.GetString()
- << "\" that does not exist.";
+ e << "READ_ELF given FILE \"" << fileNameArg << "\" that does not exist.";
this->SetError(e.str());
return false;
}
#if defined(CMAKE_USE_ELF_PARSER)
- cmELF elf(fileNameArg.GetCString());
+ cmELF elf(fileNameArg.c_str());
- if (!rpathArg.GetString().empty()) {
+ if (!arguments.RPath.empty()) {
if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) {
std::string rpath(se_rpath->Value);
std::replace(rpath.begin(), rpath.end(), ':', ';');
- this->Makefile->AddDefinition(rpathArg.GetString(), rpath.c_str());
+ this->Makefile->AddDefinition(arguments.RPath, rpath.c_str());
}
}
- if (!runpathArg.GetString().empty()) {
+ if (!arguments.RunPath.empty()) {
if (cmELF::StringEntry const* se_runpath = elf.GetRunPath()) {
std::string runpath(se_runpath->Value);
std::replace(runpath.begin(), runpath.end(), ':', ';');
- this->Makefile->AddDefinition(runpathArg.GetString(), runpath.c_str());
+ this->Makefile->AddDefinition(arguments.RunPath, runpath.c_str());
}
}
return true;
#else
std::string error = "ELF parser not available on this platform.";
- if (errorArg.GetString().empty()) {
+ if (arguments.Error.empty()) {
this->SetError(error);
return false;
}
- this->Makefile->AddDefinition(errorArg.GetString(), error.c_str());
+ this->Makefile->AddDefinition(arguments.Error, error.c_str());
return true;
#endif
}
@@ -2481,14 +1390,20 @@ bool cmFileCommand::HandleRemove(std::vector<std::string> const& args,
{
std::string message;
- std::vector<std::string>::const_iterator i = args.begin();
- i++; // Get rid of subcommand
- for (; i != args.end(); ++i) {
- std::string fileName = *i;
+ for (std::string const& arg :
+ cmMakeRange(args).advance(1)) // Get rid of subcommand
+ {
+ std::string fileName = arg;
+ if (fileName.empty()) {
+ std::string const r = recurse ? "REMOVE_RECURSE" : "REMOVE";
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING,
+ "Ignoring empty file name in " + r + ".");
+ continue;
+ }
if (!cmsys::SystemTools::FileIsFullPath(fileName)) {
fileName = this->Makefile->GetCurrentSourceDirectory();
- fileName += "/" + *i;
+ fileName += "/" + arg;
}
if (cmSystemTools::FileIsDirectory(fileName) &&
@@ -2501,44 +1416,43 @@ bool cmFileCommand::HandleRemove(std::vector<std::string> const& args,
return true;
}
+namespace {
+std::string ToNativePath(const std::string& path)
+{
+ const auto& outPath = cmSystemTools::ConvertToOutputPath(path);
+ if (outPath.size() > 1 && outPath.front() == '\"' &&
+ outPath.back() == '\"') {
+ return outPath.substr(1, outPath.size() - 2);
+ }
+ return outPath;
+}
+
+std::string ToCMakePath(const std::string& path)
+{
+ auto temp = path;
+ cmSystemTools::ConvertToUnixSlashes(temp);
+ return temp;
+}
+}
+
bool cmFileCommand::HandleCMakePathCommand(
std::vector<std::string> const& args, bool nativePath)
{
- std::vector<std::string>::const_iterator i = args.begin();
if (args.size() != 3) {
this->SetError("FILE([TO_CMAKE_PATH|TO_NATIVE_PATH] path result) must be "
"called with exactly three arguments.");
return false;
}
- i++; // Get rid of subcommand
#if defined(_WIN32) && !defined(__CYGWIN__)
char pathSep = ';';
#else
char pathSep = ':';
#endif
- std::vector<std::string> path = cmSystemTools::SplitString(*i, pathSep);
- i++;
- const char* var = i->c_str();
- std::string value;
- for (std::vector<std::string>::iterator j = path.begin(); j != path.end();
- ++j) {
- if (j != path.begin()) {
- value += ";";
- }
- if (!nativePath) {
- cmSystemTools::ConvertToUnixSlashes(*j);
- } else {
- *j = cmSystemTools::ConvertToOutputPath(*j);
- // remove double quotes in the path
- std::string& s = *j;
+ std::vector<std::string> path = cmSystemTools::SplitString(args[1], pathSep);
- if (s.size() > 1 && s.front() == '\"' && s.back() == '\"') {
- s = s.substr(1, s.size() - 2);
- }
- }
- value += *j;
- }
- this->Makefile->AddDefinition(var, value.c_str());
+ std::string value = cmJoin(
+ cmMakeRange(path).transform(nativePath ? ToNativePath : ToCMakePath), ";");
+ this->Makefile->AddDefinition(args[2], value.c_str());
return true;
}
@@ -2562,23 +1476,22 @@ size_t cmWriteToMemoryCallback(void* ptr, size_t size, size_t nmemb,
void* data)
{
int realsize = static_cast<int>(size * nmemb);
- cmFileCommandVectorOfChar* vec =
- static_cast<cmFileCommandVectorOfChar*>(data);
const char* chPtr = static_cast<char*>(ptr);
- vec->insert(vec->end(), chPtr, chPtr + realsize);
+ cmAppend(*static_cast<cmFileCommandVectorOfChar*>(data), chPtr,
+ chPtr + realsize);
return realsize;
}
size_t cmFileCommandCurlDebugCallback(CURL*, curl_infotype type, char* chPtr,
size_t size, void* data)
{
- cmFileCommandVectorOfChar* vec =
- static_cast<cmFileCommandVectorOfChar*>(data);
+ cmFileCommandVectorOfChar& vec =
+ *static_cast<cmFileCommandVectorOfChar*>(data);
switch (type) {
case CURLINFO_TEXT:
case CURLINFO_HEADER_IN:
case CURLINFO_HEADER_OUT:
- vec->insert(vec->end(), chPtr, chPtr + size);
+ cmAppend(vec, chPtr, chPtr + size);
break;
case CURLINFO_DATA_IN:
case CURLINFO_DATA_OUT:
@@ -2588,7 +1501,7 @@ size_t cmFileCommandCurlDebugCallback(CURL*, curl_infotype type, char* chPtr,
int n = sprintf(buf, "[%" KWIML_INT_PRIu64 " bytes data]\n",
static_cast<KWIML_INT_uint64_t>(size));
if (n > 0) {
- vec->insert(vec->end(), buf, buf + n);
+ cmAppend(vec, buf, buf + n);
}
} break;
default:
@@ -2651,7 +1564,7 @@ int cmFileDownloadProgressCallback(void* clientp, double dltotal, double dlnow,
if (helper->UpdatePercentage(dlnow, dltotal, status)) {
cmFileCommand* fc = helper->GetFileCommand();
cmMakefile* mf = fc->GetMakefile();
- mf->DisplayStatus(status.c_str(), -1);
+ mf->DisplayStatus(status, -1);
}
return 0;
@@ -2669,7 +1582,7 @@ int cmFileUploadProgressCallback(void* clientp, double dltotal, double dlnow,
if (helper->UpdatePercentage(ulnow, ultotal, status)) {
cmFileCommand* fc = helper->GetFileCommand();
cmMakefile* mf = fc->GetMakefile();
- mf->DisplayStatus(status.c_str(), -1);
+ mf->DisplayStatus(status, -1);
}
return 0;
@@ -2693,6 +1606,9 @@ public:
}
}
+ cURLEasyGuard(const cURLEasyGuard&) = delete;
+ cURLEasyGuard& operator=(const cURLEasyGuard&) = delete;
+
void release() { this->Easy = nullptr; }
private:
@@ -3067,7 +1983,7 @@ bool cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args)
if (!logVar.empty()) {
chunkDebug.push_back(0);
- this->Makefile->AddDefinition(logVar, &*chunkDebug.begin());
+ this->Makefile->AddDefinition(logVar, chunkDebug.data());
}
return true;
@@ -3326,14 +2242,14 @@ bool cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args)
if (!chunkResponse.empty()) {
chunkResponse.push_back(0);
log += "Response:\n";
- log += &*chunkResponse.begin();
+ log += chunkResponse.data();
log += "\n";
}
if (!chunkDebug.empty()) {
chunkDebug.push_back(0);
log += "Debug:\n";
- log += &*chunkDebug.begin();
+ log += chunkDebug.data();
log += "\n";
}
@@ -3674,44 +2590,39 @@ bool cmFileCommand::HandleCreateLinkCommand(
return false;
}
- cmCommandArgumentsHelper argHelper;
- cmCommandArgumentGroup group;
-
- cmCAString linkArg(&argHelper, "CREATE_LINK");
- cmCAString fileArg(&argHelper, nullptr);
- cmCAString newFileArg(&argHelper, nullptr);
+ std::string const& fileName = args[1];
+ std::string const& newFileName = args[2];
- cmCAString resultArg(&argHelper, "RESULT", &group);
- cmCAEnabler copyOnErrorArg(&argHelper, "COPY_ON_ERROR", &group);
- cmCAEnabler symbolicArg(&argHelper, "SYMBOLIC", &group);
+ struct Arguments
+ {
+ std::string Result;
+ bool CopyOnError = false;
+ bool Symbolic = false;
+ };
- linkArg.Follows(nullptr);
- fileArg.Follows(&linkArg);
- newFileArg.Follows(&fileArg);
- group.Follows(&newFileArg);
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("RESULT"_s, &Arguments::Result)
+ .Bind("COPY_ON_ERROR"_s, &Arguments::CopyOnError)
+ .Bind("SYMBOLIC"_s, &Arguments::Symbolic);
std::vector<std::string> unconsumedArgs;
- argHelper.Parse(&args, &unconsumedArgs);
+ Arguments const arguments =
+ parser.Parse(cmMakeRange(args).advance(3), &unconsumedArgs);
if (!unconsumedArgs.empty()) {
this->SetError("unknown argument: \"" + unconsumedArgs.front() + '\"');
return false;
}
- std::string fileName = fileArg.GetString();
- std::string newFileName = newFileArg.GetString();
-
- // Output variable for storing the result.
- const std::string& resultVar = resultArg.GetString();
-
// The system error message generated in the operation.
std::string result;
// Check if the paths are distinct.
if (fileName == newFileName) {
result = "CREATE_LINK cannot use same file and newfile";
- if (!resultVar.empty()) {
- this->Makefile->AddDefinition(resultVar, result.c_str());
+ if (!arguments.Result.empty()) {
+ this->Makefile->AddDefinition(arguments.Result, result.c_str());
return true;
}
this->SetError(result);
@@ -3719,10 +2630,10 @@ bool cmFileCommand::HandleCreateLinkCommand(
}
// Hard link requires original file to exist.
- if (!symbolicArg.IsEnabled() && !cmSystemTools::FileExists(fileName)) {
+ if (!arguments.Symbolic && !cmSystemTools::FileExists(fileName)) {
result = "Cannot hard link \'" + fileName + "\' as it does not exist.";
- if (!resultVar.empty()) {
- this->Makefile->AddDefinition(resultVar, result.c_str());
+ if (!arguments.Result.empty()) {
+ this->Makefile->AddDefinition(arguments.Result, result.c_str());
return true;
}
this->SetError(result);
@@ -3738,8 +2649,8 @@ bool cmFileCommand::HandleCreateLinkCommand(
<< "' because existing path cannot be removed: "
<< cmSystemTools::GetLastSystemError() << "\n";
- if (!resultVar.empty()) {
- this->Makefile->AddDefinition(resultVar, e.str().c_str());
+ if (!arguments.Result.empty()) {
+ this->Makefile->AddDefinition(arguments.Result, e.str().c_str());
return true;
}
this->SetError(e.str());
@@ -3750,15 +2661,15 @@ bool cmFileCommand::HandleCreateLinkCommand(
bool completed = false;
// Check if the command requires a symbolic link.
- if (symbolicArg.IsEnabled()) {
+ if (arguments.Symbolic) {
completed = cmSystemTools::CreateSymlink(fileName, newFileName, &result);
} else {
completed = cmSystemTools::CreateLink(fileName, newFileName, &result);
}
// Check if copy-on-error is enabled in the arguments.
- if (!completed && copyOnErrorArg.IsEnabled()) {
- completed = cmSystemTools::cmCopyFile(fileName, newFileName);
+ if (!completed && arguments.CopyOnError) {
+ completed = cmsys::SystemTools::CopyFileAlways(fileName, newFileName);
if (!completed) {
result = "Copy failed: " + cmSystemTools::GetLastSystemError();
}
@@ -3767,14 +2678,14 @@ bool cmFileCommand::HandleCreateLinkCommand(
// Check if the operation was successful.
if (completed) {
result = "0";
- } else if (resultVar.empty()) {
+ } else if (arguments.Result.empty()) {
// The operation failed and the result is not reported in a variable.
this->SetError(result);
return false;
}
- if (!resultVar.empty()) {
- this->Makefile->AddDefinition(resultVar, result.c_str());
+ if (!arguments.Result.empty()) {
+ this->Makefile->AddDefinition(arguments.Result, result.c_str());
}
return true;
diff --git a/Source/cmFileCopier.cxx b/Source/cmFileCopier.cxx
new file mode 100644
index 000000000..49e8cd5b3
--- /dev/null
+++ b/Source/cmFileCopier.cxx
@@ -0,0 +1,713 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmFileCopier.h"
+
+#include "cmFSPermissions.h"
+#include "cmFileCommand.h"
+#include "cmFileTimes.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmsys/Directory.hxx"
+#include "cmsys/Glob.hxx"
+
+#ifdef _WIN32
+# include "cmsys/FStream.hxx"
+#endif
+
+#include <sstream>
+#include <string.h>
+
+using namespace cmFSPermissions;
+
+cmFileCopier::cmFileCopier(cmFileCommand* command, const char* name)
+ : FileCommand(command)
+ , Makefile(command->GetMakefile())
+ , Name(name)
+ , Always(false)
+ , MatchlessFiles(true)
+ , FilePermissions(0)
+ , DirPermissions(0)
+ , CurrentMatchRule(nullptr)
+ , UseGivenPermissionsFile(false)
+ , UseGivenPermissionsDir(false)
+ , UseSourcePermissions(true)
+ , FollowSymlinkChain(false)
+ , Doing(DoingNone)
+{
+}
+
+cmFileCopier::~cmFileCopier() = default;
+
+cmFileCopier::MatchProperties cmFileCopier::CollectMatchProperties(
+ const std::string& file)
+{
+ // Match rules are case-insensitive on some platforms.
+#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
+ const std::string file_to_match = cmSystemTools::LowerCase(file);
+#else
+ const std::string& file_to_match = file;
+#endif
+
+ // Collect properties from all matching rules.
+ bool matched = false;
+ MatchProperties result;
+ for (MatchRule& mr : this->MatchRules) {
+ if (mr.Regex.find(file_to_match)) {
+ matched = true;
+ result.Exclude |= mr.Properties.Exclude;
+ result.Permissions |= mr.Properties.Permissions;
+ }
+ }
+ if (!matched && !this->MatchlessFiles) {
+ result.Exclude = !cmSystemTools::FileIsDirectory(file);
+ }
+ return result;
+}
+
+bool cmFileCopier::SetPermissions(const std::string& toFile,
+ mode_t permissions)
+{
+ if (permissions) {
+#ifdef WIN32
+ if (Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
+ // Store the mode in an NTFS alternate stream.
+ std::string mode_t_adt_filename = toFile + ":cmake_mode_t";
+
+ // Writing to an NTFS alternate stream changes the modification
+ // time, so we need to save and restore its original value.
+ cmFileTimes file_time_orig(toFile);
+ {
+ cmsys::ofstream permissionStream(mode_t_adt_filename.c_str());
+ if (permissionStream) {
+ permissionStream << std::oct << permissions << std::endl;
+ }
+ permissionStream.close();
+ }
+ file_time_orig.Store(toFile);
+ }
+#endif
+
+ if (!cmSystemTools::SetPermissions(toFile, permissions)) {
+ std::ostringstream e;
+ e << this->Name << " cannot set permissions on \"" << toFile << "\"";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+ }
+ return true;
+}
+
+// Translate an argument to a permissions bit.
+bool cmFileCopier::CheckPermissions(std::string const& arg,
+ mode_t& permissions)
+{
+ if (!cmFSPermissions::stringToModeT(arg, permissions)) {
+ std::ostringstream e;
+ e << this->Name << " given invalid permission \"" << arg << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+ return true;
+}
+
+std::string const& cmFileCopier::ToName(std::string const& fromName)
+{
+ return fromName;
+}
+
+bool cmFileCopier::ReportMissing(const std::string& fromFile)
+{
+ // The input file does not exist and installation is not optional.
+ std::ostringstream e;
+ e << this->Name << " cannot find \"" << fromFile << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+}
+
+void cmFileCopier::NotBeforeMatch(std::string const& arg)
+{
+ std::ostringstream e;
+ e << "option " << arg << " may not appear before PATTERN or REGEX.";
+ this->FileCommand->SetError(e.str());
+ this->Doing = DoingError;
+}
+
+void cmFileCopier::NotAfterMatch(std::string const& arg)
+{
+ std::ostringstream e;
+ e << "option " << arg << " may not appear after PATTERN or REGEX.";
+ this->FileCommand->SetError(e.str());
+ this->Doing = DoingError;
+}
+
+void cmFileCopier::DefaultFilePermissions()
+{
+ // Use read/write permissions.
+ this->FilePermissions = 0;
+ this->FilePermissions |= mode_owner_read;
+ this->FilePermissions |= mode_owner_write;
+ this->FilePermissions |= mode_group_read;
+ this->FilePermissions |= mode_world_read;
+}
+
+void cmFileCopier::DefaultDirectoryPermissions()
+{
+ // Use read/write/executable permissions.
+ this->DirPermissions = 0;
+ this->DirPermissions |= mode_owner_read;
+ this->DirPermissions |= mode_owner_write;
+ this->DirPermissions |= mode_owner_execute;
+ this->DirPermissions |= mode_group_read;
+ this->DirPermissions |= mode_group_execute;
+ this->DirPermissions |= mode_world_read;
+ this->DirPermissions |= mode_world_execute;
+}
+
+bool cmFileCopier::GetDefaultDirectoryPermissions(mode_t** mode)
+{
+ // check if default dir creation permissions were set
+ const char* default_dir_install_permissions = this->Makefile->GetDefinition(
+ "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
+ if (default_dir_install_permissions && *default_dir_install_permissions) {
+ std::vector<std::string> items;
+ cmSystemTools::ExpandListArgument(default_dir_install_permissions, items);
+ for (const auto& arg : items) {
+ if (!this->CheckPermissions(arg, **mode)) {
+ std::ostringstream e;
+ e << this->FileCommand->GetError()
+ << " Set with CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS "
+ "variable.";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+ }
+ } else {
+ *mode = nullptr;
+ }
+
+ return true;
+}
+
+bool cmFileCopier::Parse(std::vector<std::string> const& args)
+{
+ this->Doing = DoingFiles;
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ // Check this argument.
+ if (!this->CheckKeyword(args[i]) && !this->CheckValue(args[i])) {
+ std::ostringstream e;
+ e << "called with unknown argument \"" << args[i] << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+
+ // Quit if an argument is invalid.
+ if (this->Doing == DoingError) {
+ return false;
+ }
+ }
+
+ // Require a destination.
+ if (this->Destination.empty()) {
+ std::ostringstream e;
+ e << this->Name << " given no DESTINATION";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+
+ // If file permissions were not specified set default permissions.
+ if (!this->UseGivenPermissionsFile && !this->UseSourcePermissions) {
+ this->DefaultFilePermissions();
+ }
+
+ // If directory permissions were not specified set default permissions.
+ if (!this->UseGivenPermissionsDir && !this->UseSourcePermissions) {
+ this->DefaultDirectoryPermissions();
+ }
+
+ return true;
+}
+
+bool cmFileCopier::CheckKeyword(std::string const& arg)
+{
+ if (arg == "DESTINATION") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingDestination;
+ }
+ } else if (arg == "FILES_FROM_DIR") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingFilesFromDir;
+ }
+ } else if (arg == "PATTERN") {
+ this->Doing = DoingPattern;
+ } else if (arg == "REGEX") {
+ this->Doing = DoingRegex;
+ } else if (arg == "FOLLOW_SYMLINK_CHAIN") {
+ this->FollowSymlinkChain = true;
+ this->Doing = DoingNone;
+ } else if (arg == "EXCLUDE") {
+ // Add this property to the current match rule.
+ if (this->CurrentMatchRule) {
+ this->CurrentMatchRule->Properties.Exclude = true;
+ this->Doing = DoingNone;
+ } else {
+ this->NotBeforeMatch(arg);
+ }
+ } else if (arg == "PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->Doing = DoingPermissionsMatch;
+ } else {
+ this->NotBeforeMatch(arg);
+ }
+ } else if (arg == "FILE_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingPermissionsFile;
+ this->UseGivenPermissionsFile = true;
+ }
+ } else if (arg == "DIRECTORY_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingPermissionsDir;
+ this->UseGivenPermissionsDir = true;
+ }
+ } else if (arg == "USE_SOURCE_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->UseSourcePermissions = true;
+ }
+ } else if (arg == "NO_SOURCE_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->UseSourcePermissions = false;
+ }
+ } else if (arg == "FILES_MATCHING") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->MatchlessFiles = false;
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool cmFileCopier::CheckValue(std::string const& arg)
+{
+ switch (this->Doing) {
+ case DoingFiles:
+ this->Files.push_back(arg);
+ break;
+ case DoingDestination:
+ if (arg.empty() || cmSystemTools::FileIsFullPath(arg)) {
+ this->Destination = arg;
+ } else {
+ this->Destination = this->Makefile->GetCurrentBinaryDirectory();
+ this->Destination += "/" + arg;
+ }
+ this->Doing = DoingNone;
+ break;
+ case DoingFilesFromDir:
+ if (cmSystemTools::FileIsFullPath(arg)) {
+ this->FilesFromDir = arg;
+ } else {
+ this->FilesFromDir = this->Makefile->GetCurrentSourceDirectory();
+ this->FilesFromDir += "/" + arg;
+ }
+ cmSystemTools::ConvertToUnixSlashes(this->FilesFromDir);
+ this->Doing = DoingNone;
+ break;
+ case DoingPattern: {
+ // Convert the pattern to a regular expression. Require a
+ // leading slash and trailing end-of-string in the matched
+ // string to make sure the pattern matches only whole file
+ // names.
+ std::string regex = "/";
+ regex += cmsys::Glob::PatternToRegex(arg, false);
+ regex += "$";
+ this->MatchRules.emplace_back(regex);
+ this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
+ if (this->CurrentMatchRule->Regex.is_valid()) {
+ this->Doing = DoingNone;
+ } else {
+ std::ostringstream e;
+ e << "could not compile PATTERN \"" << arg << "\".";
+ this->FileCommand->SetError(e.str());
+ this->Doing = DoingError;
+ }
+ } break;
+ case DoingRegex:
+ this->MatchRules.emplace_back(arg);
+ this->CurrentMatchRule = &*(this->MatchRules.end() - 1);
+ if (this->CurrentMatchRule->Regex.is_valid()) {
+ this->Doing = DoingNone;
+ } else {
+ std::ostringstream e;
+ e << "could not compile REGEX \"" << arg << "\".";
+ this->FileCommand->SetError(e.str());
+ this->Doing = DoingError;
+ }
+ break;
+ case DoingPermissionsFile:
+ if (!this->CheckPermissions(arg, this->FilePermissions)) {
+ this->Doing = DoingError;
+ }
+ break;
+ case DoingPermissionsDir:
+ if (!this->CheckPermissions(arg, this->DirPermissions)) {
+ this->Doing = DoingError;
+ }
+ break;
+ case DoingPermissionsMatch:
+ if (!this->CheckPermissions(
+ arg, this->CurrentMatchRule->Properties.Permissions)) {
+ this->Doing = DoingError;
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool cmFileCopier::Run(std::vector<std::string> const& args)
+{
+ if (!this->Parse(args)) {
+ return false;
+ }
+
+ for (std::string const& f : this->Files) {
+ std::string file;
+ if (!f.empty() && !cmSystemTools::FileIsFullPath(f)) {
+ if (!this->FilesFromDir.empty()) {
+ file = this->FilesFromDir;
+ } else {
+ file = this->Makefile->GetCurrentSourceDirectory();
+ }
+ file += "/";
+ file += f;
+ } else if (!this->FilesFromDir.empty()) {
+ this->FileCommand->SetError("option FILES_FROM_DIR requires all files "
+ "to be specified as relative paths.");
+ return false;
+ } else {
+ file = f;
+ }
+
+ // Split the input file into its directory and name components.
+ std::vector<std::string> fromPathComponents;
+ cmSystemTools::SplitPath(file, fromPathComponents);
+ std::string fromName = *(fromPathComponents.end() - 1);
+ std::string fromDir = cmSystemTools::JoinPath(
+ fromPathComponents.begin(), fromPathComponents.end() - 1);
+
+ // Compute the full path to the destination file.
+ std::string toFile = this->Destination;
+ if (!this->FilesFromDir.empty()) {
+ std::string dir = cmSystemTools::GetFilenamePath(f);
+ if (!dir.empty()) {
+ toFile += "/";
+ toFile += dir;
+ }
+ }
+ std::string const& toName = this->ToName(fromName);
+ if (!toName.empty()) {
+ toFile += "/";
+ toFile += toName;
+ }
+
+ // Construct the full path to the source file. The file name may
+ // have been changed above.
+ std::string fromFile = fromDir;
+ if (!fromName.empty()) {
+ fromFile += "/";
+ fromFile += fromName;
+ }
+
+ if (!this->Install(fromFile, toFile)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmFileCopier::Install(const std::string& fromFile,
+ const std::string& toFile)
+{
+ if (fromFile.empty()) {
+ std::ostringstream e;
+ e << "INSTALL encountered an empty string input file name.";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+
+ // Collect any properties matching this file name.
+ MatchProperties match_properties = this->CollectMatchProperties(fromFile);
+
+ // Skip the file if it is excluded.
+ if (match_properties.Exclude) {
+ return true;
+ }
+
+ if (cmSystemTools::SameFile(fromFile, toFile)) {
+ return true;
+ }
+
+ std::string newFromFile = fromFile;
+ std::string newToFile = toFile;
+
+ if (this->FollowSymlinkChain &&
+ !this->InstallSymlinkChain(newFromFile, newToFile)) {
+ return false;
+ }
+
+ if (cmSystemTools::FileIsSymlink(newFromFile)) {
+ return this->InstallSymlink(newFromFile, newToFile);
+ }
+ if (cmSystemTools::FileIsDirectory(newFromFile)) {
+ return this->InstallDirectory(newFromFile, newToFile, match_properties);
+ }
+ if (cmSystemTools::FileExists(newFromFile)) {
+ return this->InstallFile(newFromFile, newToFile, match_properties);
+ }
+ return this->ReportMissing(newFromFile);
+}
+
+bool cmFileCopier::InstallSymlinkChain(std::string& fromFile,
+ std::string& toFile)
+{
+ std::string newFromFile;
+ std::string toFilePath = cmSystemTools::GetFilenamePath(toFile);
+ while (cmSystemTools::ReadSymlink(fromFile, newFromFile)) {
+ if (!cmSystemTools::FileIsFullPath(newFromFile)) {
+ std::string fromFilePath = cmSystemTools::GetFilenamePath(fromFile);
+ newFromFile = fromFilePath + "/" + newFromFile;
+ }
+
+ std::string symlinkTarget = cmSystemTools::GetFilenameName(newFromFile);
+
+ bool copy = true;
+ if (!this->Always) {
+ std::string oldSymlinkTarget;
+ if (cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget)) {
+ if (symlinkTarget == oldSymlinkTarget) {
+ copy = false;
+ }
+ }
+ }
+
+ this->ReportCopy(toFile, TypeLink, copy);
+
+ if (copy) {
+ cmSystemTools::RemoveFile(toFile);
+ cmSystemTools::MakeDirectory(toFilePath);
+
+ if (!cmSystemTools::CreateSymlink(symlinkTarget, toFile)) {
+ std::ostringstream e;
+ e << this->Name << " cannot create symlink \"" << toFile << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+ }
+
+ fromFile = newFromFile;
+ toFile = toFilePath + "/" + symlinkTarget;
+ }
+
+ return true;
+}
+
+bool cmFileCopier::InstallSymlink(const std::string& fromFile,
+ const std::string& toFile)
+{
+ // Read the original symlink.
+ std::string symlinkTarget;
+ if (!cmSystemTools::ReadSymlink(fromFile, symlinkTarget)) {
+ std::ostringstream e;
+ e << this->Name << " cannot read symlink \"" << fromFile
+ << "\" to duplicate at \"" << toFile << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+
+ // Compare the symlink value to that at the destination if not
+ // always installing.
+ bool copy = true;
+ if (!this->Always) {
+ std::string oldSymlinkTarget;
+ if (cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget)) {
+ if (symlinkTarget == oldSymlinkTarget) {
+ copy = false;
+ }
+ }
+ }
+
+ // Inform the user about this file installation.
+ this->ReportCopy(toFile, TypeLink, copy);
+
+ if (copy) {
+ // Remove the destination file so we can always create the symlink.
+ cmSystemTools::RemoveFile(toFile);
+
+ // Create destination directory if it doesn't exist
+ cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(toFile));
+
+ // Create the symlink.
+ if (!cmSystemTools::CreateSymlink(symlinkTarget, toFile)) {
+ std::ostringstream e;
+ e << this->Name << " cannot duplicate symlink \"" << fromFile
+ << "\" at \"" << toFile << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool cmFileCopier::InstallFile(const std::string& fromFile,
+ const std::string& toFile,
+ MatchProperties match_properties)
+{
+ // Determine whether we will copy the file.
+ bool copy = true;
+ if (!this->Always) {
+ // If both files exist with the same time do not copy.
+ if (!this->FileTimes.DifferS(fromFile, toFile)) {
+ copy = false;
+ }
+ }
+
+ // Inform the user about this file installation.
+ this->ReportCopy(toFile, TypeFile, copy);
+
+ // Copy the file.
+ if (copy && !cmSystemTools::CopyAFile(fromFile, toFile, true)) {
+ std::ostringstream e;
+ e << this->Name << " cannot copy file \"" << fromFile << "\" to \""
+ << toFile << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+
+ // Set the file modification time of the destination file.
+ if (copy && !this->Always) {
+ // Add write permission so we can set the file time.
+ // Permissions are set unconditionally below anyway.
+ mode_t perm = 0;
+ if (cmSystemTools::GetPermissions(toFile, perm)) {
+ cmSystemTools::SetPermissions(toFile, perm | mode_owner_write);
+ }
+ if (!cmFileTimes::Copy(fromFile, toFile)) {
+ std::ostringstream e;
+ e << this->Name << " cannot set modification time on \"" << toFile
+ << "\"";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+ }
+
+ // Set permissions of the destination file.
+ mode_t permissions =
+ (match_properties.Permissions ? match_properties.Permissions
+ : this->FilePermissions);
+ if (!permissions) {
+ // No permissions were explicitly provided but the user requested
+ // that the source file permissions be used.
+ cmSystemTools::GetPermissions(fromFile, permissions);
+ }
+ return this->SetPermissions(toFile, permissions);
+}
+
+bool cmFileCopier::InstallDirectory(const std::string& source,
+ const std::string& destination,
+ MatchProperties match_properties)
+{
+ // Inform the user about this directory installation.
+ this->ReportCopy(destination, TypeDir,
+ !cmSystemTools::FileIsDirectory(destination));
+
+ // check if default dir creation permissions were set
+ mode_t default_dir_mode_v = 0;
+ mode_t* default_dir_mode = &default_dir_mode_v;
+ if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
+ return false;
+ }
+
+ // Make sure the destination directory exists.
+ if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
+ std::ostringstream e;
+ e << this->Name << " cannot make directory \"" << destination
+ << "\": " << cmSystemTools::GetLastSystemError();
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+
+ // Compute the requested permissions for the destination directory.
+ mode_t permissions =
+ (match_properties.Permissions ? match_properties.Permissions
+ : this->DirPermissions);
+ if (!permissions) {
+ // No permissions were explicitly provided but the user requested
+ // that the source directory permissions be used.
+ cmSystemTools::GetPermissions(source, permissions);
+ }
+
+ // Compute the set of permissions required on this directory to
+ // recursively install files and subdirectories safely.
+ mode_t required_permissions =
+ mode_owner_read | mode_owner_write | mode_owner_execute;
+
+ // If the required permissions are specified it is safe to set the
+ // final permissions now. Otherwise we must add the required
+ // permissions temporarily during file installation.
+ mode_t permissions_before = 0;
+ mode_t permissions_after = 0;
+ if ((permissions & required_permissions) == required_permissions) {
+ permissions_before = permissions;
+ } else {
+ permissions_before = permissions | required_permissions;
+ permissions_after = permissions;
+ }
+
+ // Set the required permissions of the destination directory.
+ if (!this->SetPermissions(destination, permissions_before)) {
+ return false;
+ }
+
+ // Load the directory contents to traverse it recursively.
+ cmsys::Directory dir;
+ if (!source.empty()) {
+ dir.Load(source);
+ }
+ unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
+ for (unsigned long fileNum = 0; fileNum < numFiles; ++fileNum) {
+ if (!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
+ strcmp(dir.GetFile(fileNum), "..") == 0)) {
+ std::string fromPath = source;
+ fromPath += "/";
+ fromPath += dir.GetFile(fileNum);
+ std::string toPath = destination;
+ toPath += "/";
+ toPath += dir.GetFile(fileNum);
+ if (!this->Install(fromPath, toPath)) {
+ return false;
+ }
+ }
+ }
+
+ // Set the requested permissions of the destination directory.
+ return this->SetPermissions(destination, permissions_after);
+}
diff --git a/Source/cmFileCopier.h b/Source/cmFileCopier.h
new file mode 100644
index 000000000..a79a60b90
--- /dev/null
+++ b/Source/cmFileCopier.h
@@ -0,0 +1,122 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmFileCopier_h
+#define cmFileCopier_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmFileTimeCache.h"
+#include "cm_sys_stat.h"
+#include "cmsys/RegularExpression.hxx"
+
+#include <string>
+#include <vector>
+
+class cmFileCommand;
+class cmMakefile;
+
+// File installation helper class.
+struct cmFileCopier
+{
+ cmFileCopier(cmFileCommand* command, const char* name = "COPY");
+ virtual ~cmFileCopier();
+
+ bool Run(std::vector<std::string> const& args);
+
+protected:
+ cmFileCommand* FileCommand;
+ cmMakefile* Makefile;
+ const char* Name;
+ bool Always;
+ cmFileTimeCache FileTimes;
+
+ // Whether to install a file not matching any expression.
+ bool MatchlessFiles;
+
+ // Permissions for files and directories installed by this object.
+ mode_t FilePermissions;
+ mode_t DirPermissions;
+
+ // Properties set by pattern and regex match rules.
+ struct MatchProperties
+ {
+ bool Exclude = false;
+ mode_t Permissions = 0;
+ };
+ struct MatchRule
+ {
+ cmsys::RegularExpression Regex;
+ MatchProperties Properties;
+ std::string RegexString;
+ MatchRule(std::string const& regex)
+ : Regex(regex)
+ , RegexString(regex)
+ {
+ }
+ };
+ std::vector<MatchRule> MatchRules;
+
+ // Get the properties from rules matching this input file.
+ MatchProperties CollectMatchProperties(const std::string& file);
+
+ bool SetPermissions(const std::string& toFile, mode_t permissions);
+
+ // Translate an argument to a permissions bit.
+ bool CheckPermissions(std::string const& arg, mode_t& permissions);
+
+ bool InstallSymlinkChain(std::string& fromFile, std::string& toFile);
+ bool InstallSymlink(const std::string& fromFile, const std::string& toFile);
+ bool InstallFile(const std::string& fromFile, const std::string& toFile,
+ MatchProperties match_properties);
+ bool InstallDirectory(const std::string& source,
+ const std::string& destination,
+ MatchProperties match_properties);
+ virtual bool Install(const std::string& fromFile, const std::string& toFile);
+ virtual std::string const& ToName(std::string const& fromName);
+
+ enum Type
+ {
+ TypeFile,
+ TypeDir,
+ TypeLink
+ };
+ virtual void ReportCopy(const std::string&, Type, bool) {}
+ virtual bool ReportMissing(const std::string& fromFile);
+
+ MatchRule* CurrentMatchRule;
+ bool UseGivenPermissionsFile;
+ bool UseGivenPermissionsDir;
+ bool UseSourcePermissions;
+ bool FollowSymlinkChain;
+ std::string Destination;
+ std::string FilesFromDir;
+ std::vector<std::string> Files;
+ int Doing;
+
+ virtual bool Parse(std::vector<std::string> const& args);
+ enum
+ {
+ DoingNone,
+ DoingError,
+ DoingDestination,
+ DoingFilesFromDir,
+ DoingFiles,
+ DoingPattern,
+ DoingRegex,
+ DoingPermissionsFile,
+ DoingPermissionsDir,
+ DoingPermissionsMatch,
+ DoingLast1
+ };
+ virtual bool CheckKeyword(std::string const& arg);
+ virtual bool CheckValue(std::string const& arg);
+
+ void NotBeforeMatch(std::string const& arg);
+ void NotAfterMatch(std::string const& arg);
+ virtual void DefaultFilePermissions();
+ virtual void DefaultDirectoryPermissions();
+
+ bool GetDefaultDirectoryPermissions(mode_t** mode);
+};
+
+#endif
diff --git a/Source/cmFileInstaller.cxx b/Source/cmFileInstaller.cxx
new file mode 100644
index 000000000..d4f76fd86
--- /dev/null
+++ b/Source/cmFileInstaller.cxx
@@ -0,0 +1,350 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmFileInstaller.h"
+
+#include "cmFSPermissions.h"
+#include "cmFileCommand.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+#include "cm_sys_stat.h"
+
+#include <sstream>
+
+using namespace cmFSPermissions;
+
+cmFileInstaller::cmFileInstaller(cmFileCommand* command)
+ : cmFileCopier(command, "INSTALL")
+ , InstallType(cmInstallType_FILES)
+ , Optional(false)
+ , MessageAlways(false)
+ , MessageLazy(false)
+ , MessageNever(false)
+ , DestDirLength(0)
+{
+ // Installation does not use source permissions by default.
+ this->UseSourcePermissions = false;
+ // Check whether to copy files always or only if they have changed.
+ std::string install_always;
+ if (cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS", install_always)) {
+ this->Always = cmSystemTools::IsOn(install_always);
+ }
+ // Get the current manifest.
+ this->Manifest =
+ this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES");
+}
+cmFileInstaller::~cmFileInstaller()
+{
+ // Save the updated install manifest.
+ this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
+ this->Manifest.c_str());
+}
+
+void cmFileInstaller::ManifestAppend(std::string const& file)
+{
+ if (!this->Manifest.empty()) {
+ this->Manifest += ";";
+ }
+ this->Manifest += file.substr(this->DestDirLength);
+}
+
+std::string const& cmFileInstaller::ToName(std::string const& fromName)
+{
+ return this->Rename.empty() ? fromName : this->Rename;
+}
+
+void cmFileInstaller::ReportCopy(const std::string& toFile, Type type,
+ bool copy)
+{
+ if (!this->MessageNever && (copy || !this->MessageLazy)) {
+ std::string message = (copy ? "Installing: " : "Up-to-date: ");
+ message += toFile;
+ this->Makefile->DisplayStatus(message, -1);
+ }
+ if (type != TypeDir) {
+ // Add the file to the manifest.
+ this->ManifestAppend(toFile);
+ }
+}
+bool cmFileInstaller::ReportMissing(const std::string& fromFile)
+{
+ return (this->Optional || this->cmFileCopier::ReportMissing(fromFile));
+}
+bool cmFileInstaller::Install(const std::string& fromFile,
+ const std::string& toFile)
+{
+ // Support installing from empty source to make a directory.
+ if (this->InstallType == cmInstallType_DIRECTORY && fromFile.empty()) {
+ return this->InstallDirectory(fromFile, toFile, MatchProperties());
+ }
+ return this->cmFileCopier::Install(fromFile, toFile);
+}
+
+void cmFileInstaller::DefaultFilePermissions()
+{
+ this->cmFileCopier::DefaultFilePermissions();
+ // Add execute permissions based on the target type.
+ switch (this->InstallType) {
+ case cmInstallType_SHARED_LIBRARY:
+ case cmInstallType_MODULE_LIBRARY:
+ if (this->Makefile->IsOn("CMAKE_INSTALL_SO_NO_EXE")) {
+ break;
+ }
+ CM_FALLTHROUGH;
+ case cmInstallType_EXECUTABLE:
+ case cmInstallType_PROGRAMS:
+ this->FilePermissions |= mode_owner_execute;
+ this->FilePermissions |= mode_group_execute;
+ this->FilePermissions |= mode_world_execute;
+ break;
+ default:
+ break;
+ }
+}
+
+bool cmFileInstaller::Parse(std::vector<std::string> const& args)
+{
+ if (!this->cmFileCopier::Parse(args)) {
+ return false;
+ }
+
+ if (!this->Rename.empty()) {
+ if (!this->FilesFromDir.empty()) {
+ this->FileCommand->SetError("INSTALL option RENAME may not be "
+ "combined with FILES_FROM_DIR.");
+ return false;
+ }
+ if (this->InstallType != cmInstallType_FILES &&
+ this->InstallType != cmInstallType_PROGRAMS) {
+ this->FileCommand->SetError("INSTALL option RENAME may be used "
+ "only with FILES or PROGRAMS.");
+ return false;
+ }
+ if (this->Files.size() > 1) {
+ this->FileCommand->SetError("INSTALL option RENAME may be used "
+ "only with one file.");
+ return false;
+ }
+ }
+
+ if (!this->HandleInstallDestination()) {
+ return false;
+ }
+
+ if (((this->MessageAlways ? 1 : 0) + (this->MessageLazy ? 1 : 0) +
+ (this->MessageNever ? 1 : 0)) > 1) {
+ this->FileCommand->SetError("INSTALL options MESSAGE_ALWAYS, "
+ "MESSAGE_LAZY, and MESSAGE_NEVER "
+ "are mutually exclusive.");
+ return false;
+ }
+
+ return true;
+}
+
+bool cmFileInstaller::CheckKeyword(std::string const& arg)
+{
+ if (arg == "TYPE") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingType;
+ }
+ } else if (arg == "FILES") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingFiles;
+ }
+ } else if (arg == "RENAME") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingRename;
+ }
+ } else if (arg == "OPTIONAL") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->Optional = true;
+ }
+ } else if (arg == "MESSAGE_ALWAYS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->MessageAlways = true;
+ }
+ } else if (arg == "MESSAGE_LAZY") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->MessageLazy = true;
+ }
+ } else if (arg == "MESSAGE_NEVER") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingNone;
+ this->MessageNever = true;
+ }
+ } else if (arg == "PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->Doing = DoingPermissionsMatch;
+ } else {
+ // file(INSTALL) aliases PERMISSIONS to FILE_PERMISSIONS
+ this->Doing = DoingPermissionsFile;
+ this->UseGivenPermissionsFile = true;
+ }
+ } else if (arg == "DIR_PERMISSIONS") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ // file(INSTALL) aliases DIR_PERMISSIONS to DIRECTORY_PERMISSIONS
+ this->Doing = DoingPermissionsDir;
+ this->UseGivenPermissionsDir = true;
+ }
+ } else if (arg == "COMPONENTS" || arg == "CONFIGURATIONS" ||
+ arg == "PROPERTIES") {
+ std::ostringstream e;
+ e << "INSTALL called with old-style " << arg << " argument. "
+ << "This script was generated with an older version of CMake. "
+ << "Re-run this cmake version on your build tree.";
+ this->FileCommand->SetError(e.str());
+ this->Doing = DoingError;
+ } else {
+ return this->cmFileCopier::CheckKeyword(arg);
+ }
+ return true;
+}
+
+bool cmFileInstaller::CheckValue(std::string const& arg)
+{
+ switch (this->Doing) {
+ case DoingType:
+ if (!this->GetTargetTypeFromString(arg)) {
+ this->Doing = DoingError;
+ }
+ break;
+ case DoingRename:
+ this->Rename = arg;
+ break;
+ default:
+ return this->cmFileCopier::CheckValue(arg);
+ }
+ return true;
+}
+
+bool cmFileInstaller::GetTargetTypeFromString(const std::string& stype)
+{
+ if (stype == "EXECUTABLE") {
+ this->InstallType = cmInstallType_EXECUTABLE;
+ } else if (stype == "FILE") {
+ this->InstallType = cmInstallType_FILES;
+ } else if (stype == "PROGRAM") {
+ this->InstallType = cmInstallType_PROGRAMS;
+ } else if (stype == "STATIC_LIBRARY") {
+ this->InstallType = cmInstallType_STATIC_LIBRARY;
+ } else if (stype == "SHARED_LIBRARY") {
+ this->InstallType = cmInstallType_SHARED_LIBRARY;
+ } else if (stype == "MODULE") {
+ this->InstallType = cmInstallType_MODULE_LIBRARY;
+ } else if (stype == "DIRECTORY") {
+ this->InstallType = cmInstallType_DIRECTORY;
+ } else {
+ std::ostringstream e;
+ e << "Option TYPE given unknown value \"" << stype << "\".";
+ this->FileCommand->SetError(e.str());
+ return false;
+ }
+ return true;
+}
+
+bool cmFileInstaller::HandleInstallDestination()
+{
+ std::string& destination = this->Destination;
+
+ // allow for / to be a valid destination
+ if (destination.size() < 2 && destination != "/") {
+ this->FileCommand->SetError("called with inappropriate arguments. "
+ "No DESTINATION provided or .");
+ return false;
+ }
+
+ std::string sdestdir;
+ if (cmSystemTools::GetEnv("DESTDIR", sdestdir) && !sdestdir.empty()) {
+ cmSystemTools::ConvertToUnixSlashes(sdestdir);
+ char ch1 = destination[0];
+ char ch2 = destination[1];
+ char ch3 = 0;
+ if (destination.size() > 2) {
+ ch3 = destination[2];
+ }
+ int skip = 0;
+ if (ch1 != '/') {
+ int relative = 0;
+ if (((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z')) &&
+ ch2 == ':') {
+ // Assume windows
+ // let's do some destdir magic:
+ skip = 2;
+ if (ch3 != '/') {
+ relative = 1;
+ }
+ } else {
+ relative = 1;
+ }
+ if (relative) {
+ // This is relative path on unix or windows. Since we are doing
+ // destdir, this case does not make sense.
+ this->FileCommand->SetError(
+ "called with relative DESTINATION. This "
+ "does not make sense when using DESTDIR. Specify "
+ "absolute path or remove DESTDIR environment variable.");
+ return false;
+ }
+ } else {
+ if (ch2 == '/') {
+ // looks like a network path.
+ std::string message =
+ "called with network path DESTINATION. This "
+ "does not make sense when using DESTDIR. Specify local "
+ "absolute path or remove DESTDIR environment variable."
+ "\nDESTINATION=\n";
+ message += destination;
+ this->FileCommand->SetError(message);
+ return false;
+ }
+ }
+ destination = sdestdir + destination.substr(skip);
+ this->DestDirLength = int(sdestdir.size());
+ }
+
+ // check if default dir creation permissions were set
+ mode_t default_dir_mode_v = 0;
+ mode_t* default_dir_mode = &default_dir_mode_v;
+ if (!this->GetDefaultDirectoryPermissions(&default_dir_mode)) {
+ return false;
+ }
+
+ if (this->InstallType != cmInstallType_DIRECTORY) {
+ if (!cmSystemTools::FileExists(destination)) {
+ if (!cmSystemTools::MakeDirectory(destination, default_dir_mode)) {
+ std::string errstring = "cannot create directory: " + destination +
+ ". Maybe need administrative privileges.";
+ this->FileCommand->SetError(errstring);
+ return false;
+ }
+ }
+ if (!cmSystemTools::FileIsDirectory(destination)) {
+ std::string errstring =
+ "INSTALL destination: " + destination + " is not a directory.";
+ this->FileCommand->SetError(errstring);
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/Source/cmFileInstaller.h b/Source/cmFileInstaller.h
new file mode 100644
index 000000000..312529aa8
--- /dev/null
+++ b/Source/cmFileInstaller.h
@@ -0,0 +1,55 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmFileInstaller_h
+#define cmFileInstaller_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmFileCopier.h"
+
+#include "cmInstallType.h"
+
+#include <string>
+#include <vector>
+
+class cmFileCommand;
+
+struct cmFileInstaller : public cmFileCopier
+{
+ cmFileInstaller(cmFileCommand* command);
+ ~cmFileInstaller() override;
+
+protected:
+ cmInstallType InstallType;
+ bool Optional;
+ bool MessageAlways;
+ bool MessageLazy;
+ bool MessageNever;
+ int DestDirLength;
+ std::string Rename;
+
+ std::string Manifest;
+ void ManifestAppend(std::string const& file);
+
+ std::string const& ToName(std::string const& fromName) override;
+
+ void ReportCopy(const std::string& toFile, Type type, bool copy) override;
+ bool ReportMissing(const std::string& fromFile) override;
+ bool Install(const std::string& fromFile,
+ const std::string& toFile) override;
+
+ bool Parse(std::vector<std::string> const& args) override;
+ enum
+ {
+ DoingType = DoingLast1,
+ DoingRename,
+ DoingLast2
+ };
+ bool CheckKeyword(std::string const& arg) override;
+ bool CheckValue(std::string const& arg) override;
+ void DefaultFilePermissions() override;
+ bool GetTargetTypeFromString(const std::string& stype);
+ bool HandleInstallDestination();
+};
+
+#endif
diff --git a/Source/cmFilePathChecksum.cxx b/Source/cmFilePathChecksum.cxx
index 2cffa7c5b..47a223a20 100644
--- a/Source/cmFilePathChecksum.cxx
+++ b/Source/cmFilePathChecksum.cxx
@@ -74,7 +74,7 @@ std::string cmFilePathChecksum::get(std::string const& filePath) const
cmCryptoHash(cmCryptoHash::AlgoSHA256).ByteHashString(relSeed + relPath);
// Convert binary checksum to string
- return cmBase32Encoder().encodeString(&hashBytes.front(), hashBytes.size(),
+ return cmBase32Encoder().encodeString(hashBytes.data(), hashBytes.size(),
false);
}
diff --git a/Source/cmFileTime.cxx b/Source/cmFileTime.cxx
new file mode 100644
index 000000000..253457ff2
--- /dev/null
+++ b/Source/cmFileTime.cxx
@@ -0,0 +1,49 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileTime.h"
+
+#include <string>
+#include <time.h>
+
+// Use a platform-specific API to get file times efficiently.
+#if !defined(_WIN32) || defined(__CYGWIN__)
+# include "cm_sys_stat.h"
+#else
+# include "cmsys/Encoding.hxx"
+# include <windows.h>
+#endif
+
+bool cmFileTime::Load(std::string const& fileName)
+{
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ // POSIX version. Use the stat function.
+ struct stat fst;
+ if (::stat(fileName.c_str(), &fst) != 0) {
+ return false;
+ }
+# if CMake_STAT_HAS_ST_MTIM
+ // Nanosecond resolution
+ this->NS = fst.st_mtim.tv_sec * NsPerS + fst.st_mtim.tv_nsec;
+# elif CMake_STAT_HAS_ST_MTIMESPEC
+ // Nanosecond resolution
+ this->NS = fst.st_mtimespec.tv_sec * NsPerS + fst.st_mtimespec.tv_nsec;
+# else
+ // Second resolution
+ this->NS = fst.st_mtime * NsPerS;
+# endif
+#else
+ // Windows version. Get the modification time from extended file attributes.
+ WIN32_FILE_ATTRIBUTE_DATA fdata;
+ if (!GetFileAttributesExW(cmsys::Encoding::ToWide(fileName).c_str(),
+ GetFileExInfoStandard, &fdata)) {
+ return false;
+ }
+
+ // Copy the file time to the output location.
+ this->NS = (static_cast<NSC>(fdata.ftLastWriteTime.dwHighDateTime) << 32) |
+ static_cast<NSC>(fdata.ftLastWriteTime.dwLowDateTime);
+ // The file time resolution is 100 ns.
+ this->NS *= 100;
+#endif
+ return true;
+}
diff --git a/Source/cmFileTime.h b/Source/cmFileTime.h
new file mode 100644
index 000000000..d4de4e033
--- /dev/null
+++ b/Source/cmFileTime.h
@@ -0,0 +1,130 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmFileTime_h
+#define cmFileTime_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+
+/** \class cmFileTime
+ * \brief Abstract file modification time with support for comparison with
+ * other file modification times.
+ */
+class cmFileTime
+{
+public:
+ typedef long long NSC;
+ static constexpr NSC NsPerS = 1000000000;
+
+ cmFileTime() = default;
+ ~cmFileTime() = default;
+
+ /**
+ * @brief Loads the file time of fileName from the file system
+ * @return true on success
+ */
+ bool Load(std::string const& fileName);
+
+ /**
+ * @brief Return true if this is older than ftm
+ */
+ bool Older(cmFileTime const& ftm) const { return (this->NS - ftm.NS) < 0; }
+
+ /**
+ * @brief Return true if this is newer than ftm
+ */
+ bool Newer(cmFileTime const& ftm) const { return (ftm.NS - this->NS) < 0; }
+
+ /**
+ * @brief Return true if this is the same as ftm
+ */
+ bool Equal(cmFileTime const& ftm) const { return this->NS == ftm.NS; }
+
+ /**
+ * @brief Return true if this is not the same as ftm
+ */
+ bool Differ(cmFileTime const& ftm) const { return this->NS != ftm.NS; }
+
+ /**
+ * @brief Compare file modification times.
+ * @return -1, 0, +1 for this older, same, or newer than ftm.
+ */
+ int Compare(cmFileTime const& ftm) const
+ {
+ NSC const diff = this->NS - ftm.NS;
+ if (diff == 0) {
+ return 0;
+ }
+ return (diff < 0) ? -1 : 1;
+ }
+
+ // -- Comparison in second resolution
+
+ /**
+ * @brief Return true if this is at least a second older than ftm
+ */
+ bool OlderS(cmFileTime const& ftm) const
+ {
+ return (ftm.NS - this->NS) >= cmFileTime::NsPerS;
+ }
+
+ /**
+ * @brief Return true if this is at least a second newer than ftm
+ */
+ bool NewerS(cmFileTime const& ftm) const
+ {
+ return (this->NS - ftm.NS) >= cmFileTime::NsPerS;
+ }
+
+ /**
+ * @brief Return true if this is within the same second as ftm
+ */
+ bool EqualS(cmFileTime const& ftm) const
+ {
+ NSC diff = this->NS - ftm.NS;
+ if (diff < 0) {
+ diff = -diff;
+ }
+ return (diff < cmFileTime::NsPerS);
+ }
+
+ /**
+ * @brief Return true if this is older or newer than ftm by at least a second
+ */
+ bool DifferS(cmFileTime const& ftm) const
+ {
+ NSC diff = this->NS - ftm.NS;
+ if (diff < 0) {
+ diff = -diff;
+ }
+ return (diff >= cmFileTime::NsPerS);
+ }
+
+ /**
+ * @brief Compare file modification times.
+ * @return -1: this at least a second older, 0: this within the same second
+ * as ftm, +1: this at least a second newer than ftm.
+ */
+ int CompareS(cmFileTime const& ftm) const
+ {
+ NSC const diff = this->NS - ftm.NS;
+ if (diff <= -cmFileTime::NsPerS) {
+ return -1;
+ }
+ if (diff >= cmFileTime::NsPerS) {
+ return 1;
+ }
+ return 0;
+ }
+
+ /**
+ * @brief The file modification time in nanoseconds
+ */
+ NSC GetNS() const { return this->NS; }
+
+private:
+ NSC NS = 0;
+};
+
+#endif
diff --git a/Source/cmFileTimeCache.cxx b/Source/cmFileTimeCache.cxx
new file mode 100644
index 000000000..24d6bf6e1
--- /dev/null
+++ b/Source/cmFileTimeCache.cxx
@@ -0,0 +1,62 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileTimeCache.h"
+
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+cmFileTimeCache::cmFileTimeCache() = default;
+
+cmFileTimeCache::~cmFileTimeCache() = default;
+
+bool cmFileTimeCache::Load(std::string const& fileName, cmFileTime& fileTime)
+{
+ // Use the stored time if available.
+ {
+ auto fit = this->Cache.find(fileName);
+ if (fit != this->Cache.end()) {
+ fileTime = fit->second;
+ return true;
+ }
+ }
+ // Read file time from OS
+ if (!fileTime.Load(fileName)) {
+ return false;
+ }
+ // Store file time in cache
+ this->Cache[fileName] = fileTime;
+ return true;
+}
+
+bool cmFileTimeCache::Remove(std::string const& fileName)
+{
+ return (this->Cache.erase(fileName) != 0);
+}
+
+bool cmFileTimeCache::Compare(std::string const& f1, std::string const& f2,
+ int* result)
+{
+ // Get the modification time for each file.
+ cmFileTime ft1, ft2;
+ if (this->Load(f1, ft1) && this->Load(f2, ft2)) {
+ // Compare the two modification times.
+ *result = ft1.Compare(ft2);
+ return true;
+ }
+ // No comparison available. Default to the same time.
+ *result = 0;
+ return false;
+}
+
+bool cmFileTimeCache::DifferS(std::string const& f1, std::string const& f2)
+{
+ // Get the modification time for each file.
+ cmFileTime ft1, ft2;
+ if (this->Load(f1, ft1) && this->Load(f2, ft2)) {
+ // Compare the two modification times.
+ return ft1.DifferS(ft2);
+ }
+ // No comparison available. Default to different times.
+ return true;
+}
diff --git a/Source/cmFileTimeCache.h b/Source/cmFileTimeCache.h
new file mode 100644
index 000000000..4f1a3a253
--- /dev/null
+++ b/Source/cmFileTimeCache.h
@@ -0,0 +1,56 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmFileTimeCache_h
+#define cmFileTimeCache_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmFileTime.h" // IWYU pragma: keep
+#include <string>
+#include <unordered_map>
+
+/** \class cmFileTimeCache
+ * \brief Caches file modification times in an internal map for fast lookups.
+ */
+class cmFileTimeCache
+{
+public:
+ cmFileTimeCache();
+ ~cmFileTimeCache();
+
+ cmFileTimeCache(const cmFileTimeCache&) = delete;
+ cmFileTimeCache& operator=(const cmFileTimeCache&) = delete;
+
+ /**
+ * @brief Loads the file time from the cache or the file system.
+ * @return true on success
+ */
+ bool Load(std::string const& fileName, cmFileTime& fileTime);
+
+ /**
+ * @brief Removes a file time from the cache
+ * @return true if the file was found in the cache and removed
+ */
+ bool Remove(std::string const& fileName);
+
+ /**
+ * @brief Compare file modification times.
+ * @return true for successful comparison and false for error.
+ *
+ * When true is returned, result has -1, 0, +1 for
+ * f1 older, same, or newer than f2.
+ */
+ bool Compare(std::string const& f1, std::string const& f2, int* result);
+
+ /**
+ * @brief Compare file modification times.
+ * @return true unless both files exist and have modification times less
+ * than 1 second apart.
+ */
+ bool DifferS(std::string const& f1, std::string const& f2);
+
+private:
+ std::unordered_map<std::string, cmFileTime> Cache;
+};
+
+#endif
diff --git a/Source/cmFileTimeComparison.cxx b/Source/cmFileTimeComparison.cxx
deleted file mode 100644
index 8b3911e4b..000000000
--- a/Source/cmFileTimeComparison.cxx
+++ /dev/null
@@ -1,233 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmFileTimeComparison.h"
-
-#include <string>
-#include <time.h>
-#include <unordered_map>
-#include <utility>
-
-// Use a platform-specific API to get file times efficiently.
-#if !defined(_WIN32) || defined(__CYGWIN__)
-# include "cm_sys_stat.h"
-# define cmFileTimeComparison_Type struct stat
-#else
-# include "cmsys/Encoding.hxx"
-# include <windows.h>
-# define cmFileTimeComparison_Type FILETIME
-#endif
-
-class cmFileTimeComparisonInternal
-{
-public:
- // Internal comparison method.
- inline bool FileTimeCompare(const std::string& f1, const std::string& f2,
- int* result);
-
- bool FileTimesDiffer(const std::string& f1, const std::string& f2);
-
-private:
- typedef std::unordered_map<std::string, cmFileTimeComparison_Type>
- FileStatsMap;
- FileStatsMap Files;
-
- // Internal methods to lookup and compare modification times.
- inline bool Stat(const std::string& fname, cmFileTimeComparison_Type* st);
- inline int Compare(cmFileTimeComparison_Type* st1,
- cmFileTimeComparison_Type* st2);
- inline bool TimesDiffer(cmFileTimeComparison_Type* st1,
- cmFileTimeComparison_Type* st2);
-};
-
-bool cmFileTimeComparisonInternal::Stat(const std::string& fname,
- cmFileTimeComparison_Type* st)
-{
- // Use the stored time if available.
- cmFileTimeComparisonInternal::FileStatsMap::iterator fit =
- this->Files.find(fname);
- if (fit != this->Files.end()) {
- *st = fit->second;
- return true;
- }
-
-#if !defined(_WIN32) || defined(__CYGWIN__)
- // POSIX version. Use the stat function.
- int res = ::stat(fname.c_str(), st);
- if (res != 0) {
- return false;
- }
-#else
- // Windows version. Get the modification time from extended file
- // attributes.
- WIN32_FILE_ATTRIBUTE_DATA fdata;
- if (!GetFileAttributesExW(cmsys::Encoding::ToWide(fname).c_str(),
- GetFileExInfoStandard, &fdata)) {
- return false;
- }
-
- // Copy the file time to the output location.
- *st = fdata.ftLastWriteTime;
-#endif
-
- // Store the time for future use.
- this->Files[fname] = *st;
- return true;
-}
-
-cmFileTimeComparison::cmFileTimeComparison()
-{
- this->Internals = new cmFileTimeComparisonInternal;
-}
-
-cmFileTimeComparison::~cmFileTimeComparison()
-{
- delete this->Internals;
-}
-
-bool cmFileTimeComparison::FileTimeCompare(const std::string& f1,
- const std::string& f2, int* result)
-{
- return this->Internals->FileTimeCompare(f1, f2, result);
-}
-
-bool cmFileTimeComparison::FileTimesDiffer(const std::string& f1,
- const std::string& f2)
-{
- return this->Internals->FileTimesDiffer(f1, f2);
-}
-
-int cmFileTimeComparisonInternal::Compare(cmFileTimeComparison_Type* s1,
- cmFileTimeComparison_Type* s2)
-{
-#if !defined(_WIN32) || defined(__CYGWIN__)
-# if CMake_STAT_HAS_ST_MTIM
- // Compare using nanosecond resolution.
- if (s1->st_mtim.tv_sec < s2->st_mtim.tv_sec) {
- return -1;
- }
- if (s1->st_mtim.tv_sec > s2->st_mtim.tv_sec) {
- return 1;
- }
- if (s1->st_mtim.tv_nsec < s2->st_mtim.tv_nsec) {
- return -1;
- }
- if (s1->st_mtim.tv_nsec > s2->st_mtim.tv_nsec) {
- return 1;
- }
-# elif CMake_STAT_HAS_ST_MTIMESPEC
- // Compare using nanosecond resolution.
- if (s1->st_mtimespec.tv_sec < s2->st_mtimespec.tv_sec) {
- return -1;
- }
- if (s1->st_mtimespec.tv_sec > s2->st_mtimespec.tv_sec) {
- return 1;
- }
- if (s1->st_mtimespec.tv_nsec < s2->st_mtimespec.tv_nsec) {
- return -1;
- }
- if (s1->st_mtimespec.tv_nsec > s2->st_mtimespec.tv_nsec) {
- return 1;
- }
-# else
- // Compare using 1 second resolution.
- if (s1->st_mtime < s2->st_mtime) {
- return -1;
- }
- if (s1->st_mtime > s2->st_mtime) {
- return 1;
- }
-# endif
- // Files have the same time.
- return 0;
-#else
- // Compare using system-provided function.
- return (int)CompareFileTime(s1, s2);
-#endif
-}
-
-bool cmFileTimeComparisonInternal::TimesDiffer(cmFileTimeComparison_Type* s1,
- cmFileTimeComparison_Type* s2)
-{
-#if !defined(_WIN32) || defined(__CYGWIN__)
-# if CMake_STAT_HAS_ST_MTIM
- // Times are integers in units of 1ns.
- long long bil = 1000000000;
- long long t1 = s1->st_mtim.tv_sec * bil + s1->st_mtim.tv_nsec;
- long long t2 = s2->st_mtim.tv_sec * bil + s2->st_mtim.tv_nsec;
- if (t1 < t2) {
- return (t2 - t1) >= bil;
- }
- if (t2 < t1) {
- return (t1 - t2) >= bil;
- }
- return false;
-# elif CMake_STAT_HAS_ST_MTIMESPEC
- // Times are integers in units of 1ns.
- long long bil = 1000000000;
- long long t1 = s1->st_mtimespec.tv_sec * bil + s1->st_mtimespec.tv_nsec;
- long long t2 = s2->st_mtimespec.tv_sec * bil + s2->st_mtimespec.tv_nsec;
- if (t1 < t2) {
- return (t2 - t1) >= bil;
- }
- if (t2 < t1) {
- return (t1 - t2) >= bil;
- }
- return false;
-# else
- // Times are integers in units of 1s.
- if (s1->st_mtime < s2->st_mtime) {
- return (s2->st_mtime - s1->st_mtime) >= 1;
- }
- if (s1->st_mtime > s2->st_mtime) {
- return (s1->st_mtime - s2->st_mtime) >= 1;
- }
- return false;
-# endif
-#else
- // Times are integers in units of 100ns.
- LARGE_INTEGER t1;
- LARGE_INTEGER t2;
- t1.LowPart = s1->dwLowDateTime;
- t1.HighPart = s1->dwHighDateTime;
- t2.LowPart = s2->dwLowDateTime;
- t2.HighPart = s2->dwHighDateTime;
- if (t1.QuadPart < t2.QuadPart) {
- return (t2.QuadPart - t1.QuadPart) >= static_cast<LONGLONG>(10000000);
- } else if (t2.QuadPart < t1.QuadPart) {
- return (t1.QuadPart - t2.QuadPart) >= static_cast<LONGLONG>(10000000);
- } else {
- return false;
- }
-#endif
-}
-
-bool cmFileTimeComparisonInternal::FileTimeCompare(const std::string& f1,
- const std::string& f2,
- int* result)
-{
- // Get the modification time for each file.
- cmFileTimeComparison_Type s1;
- cmFileTimeComparison_Type s2;
- if (this->Stat(f1, &s1) && this->Stat(f2, &s2)) {
- // Compare the two modification times.
- *result = this->Compare(&s1, &s2);
- return true;
- }
- // No comparison available. Default to the same time.
- *result = 0;
- return false;
-}
-
-bool cmFileTimeComparisonInternal::FileTimesDiffer(const std::string& f1,
- const std::string& f2)
-{
- // Get the modification time for each file.
- cmFileTimeComparison_Type s1;
- cmFileTimeComparison_Type s2;
- if (this->Stat(f1, &s1) && this->Stat(f2, &s2)) {
- // Compare the two modification times.
- return this->TimesDiffer(&s1, &s2);
- }
- // No comparison available. Default to different times.
- return true;
-}
diff --git a/Source/cmFileTimeComparison.h b/Source/cmFileTimeComparison.h
deleted file mode 100644
index 5f74e3499..000000000
--- a/Source/cmFileTimeComparison.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#ifndef cmFileTimeComparison_h
-#define cmFileTimeComparison_h
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <string>
-
-class cmFileTimeComparisonInternal;
-
-/** \class cmFileTimeComparison
- * \brief Helper class for comparing file modification times.
- *
- * Compare file modification times or test if file modification times differ.
- */
-class cmFileTimeComparison
-{
-public:
- cmFileTimeComparison();
- ~cmFileTimeComparison();
-
- /**
- * Compare file modification times.
- * Return true for successful comparison and false for error.
- * When true is returned, result has -1, 0, +1 for
- * f1 older, same, or newer than f2.
- */
- bool FileTimeCompare(const std::string& f1, const std::string& f2,
- int* result);
-
- /**
- * Compare file modification times. Return true unless both files
- * exist and have modification times less than 1 second apart.
- */
- bool FileTimesDiffer(const std::string& f1, const std::string& f2);
-
-protected:
- cmFileTimeComparisonInternal* Internals;
-};
-
-#endif
diff --git a/Source/cmFileTimes.cxx b/Source/cmFileTimes.cxx
new file mode 100644
index 000000000..fd4f6797f
--- /dev/null
+++ b/Source/cmFileTimes.cxx
@@ -0,0 +1,127 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmFileTimes.h"
+
+#include "cmAlgorithms.h"
+#include "cm_sys_stat.h"
+
+#include <utility>
+
+#if defined(_WIN32)
+# include "cmSystemTools.h"
+# include <windows.h>
+#else
+# include <utime.h>
+#endif
+
+#if defined(_WIN32) && \
+ (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__MINGW32__))
+# include <io.h>
+#endif
+
+#ifdef _WIN32
+class cmFileTimes::WindowsHandle
+{
+public:
+ WindowsHandle(HANDLE h)
+ : handle_(h)
+ {
+ }
+ ~WindowsHandle()
+ {
+ if (this->handle_ != INVALID_HANDLE_VALUE) {
+ CloseHandle(this->handle_);
+ }
+ }
+ explicit operator bool() const
+ {
+ return this->handle_ != INVALID_HANDLE_VALUE;
+ }
+ bool operator!() const { return this->handle_ == INVALID_HANDLE_VALUE; }
+ operator HANDLE() const { return this->handle_; }
+
+private:
+ HANDLE handle_;
+};
+#endif
+
+class cmFileTimes::Times
+{
+public:
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ FILETIME timeCreation;
+ FILETIME timeLastAccess;
+ FILETIME timeLastWrite;
+#else
+ struct utimbuf timeBuf;
+#endif
+};
+
+cmFileTimes::cmFileTimes() = default;
+cmFileTimes::cmFileTimes(std::string const& fileName)
+{
+ Load(fileName);
+}
+cmFileTimes::~cmFileTimes() = default;
+
+bool cmFileTimes::Load(std::string const& fileName)
+{
+ std::unique_ptr<Times> ptr;
+ if (IsValid()) {
+ // Invalidate this and re-use times
+ ptr.swap(this->times);
+ } else {
+ ptr = cm::make_unique<Times>();
+ }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ cmFileTimes::WindowsHandle handle =
+ CreateFileW(cmSystemTools::ConvertToWindowsExtendedPath(fileName).c_str(),
+ GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, 0);
+ if (!handle) {
+ return false;
+ }
+ if (!GetFileTime(handle, &ptr->timeCreation, &ptr->timeLastAccess,
+ &ptr->timeLastWrite)) {
+ return false;
+ }
+#else
+ struct stat st;
+ if (stat(fileName.c_str(), &st) < 0) {
+ return false;
+ }
+ ptr->timeBuf.actime = st.st_atime;
+ ptr->timeBuf.modtime = st.st_mtime;
+#endif
+ // Accept times
+ this->times = std::move(ptr);
+ return true;
+}
+
+bool cmFileTimes::Store(std::string const& fileName) const
+{
+ if (!IsValid()) {
+ return false;
+ }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ cmFileTimes::WindowsHandle handle = CreateFileW(
+ cmSystemTools::ConvertToWindowsExtendedPath(fileName).c_str(),
+ FILE_WRITE_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
+ if (!handle) {
+ return false;
+ }
+ return SetFileTime(handle, &this->times->timeCreation,
+ &this->times->timeLastAccess,
+ &this->times->timeLastWrite) != 0;
+#else
+ return utime(fileName.c_str(), &this->times->timeBuf) >= 0;
+#endif
+}
+
+bool cmFileTimes::Copy(std::string const& fromFile, std::string const& toFile)
+{
+ cmFileTimes fileTimes;
+ return (fileTimes.Load(fromFile) && fileTimes.Store(toFile));
+}
diff --git a/Source/cmFileTimes.h b/Source/cmFileTimes.h
new file mode 100644
index 000000000..cbf0fe20a
--- /dev/null
+++ b/Source/cmFileTimes.h
@@ -0,0 +1,40 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmFileTimes_h
+#define cmFileTimes_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <memory> // IWYU pragma: keep
+#include <string>
+
+/** \class cmFileTimes
+ * \brief Loads and stores file times.
+ */
+class cmFileTimes
+{
+public:
+ cmFileTimes();
+ //! Calls Load()
+ cmFileTimes(std::string const& fileName);
+ ~cmFileTimes();
+
+ //! @return true, if file times were loaded successfully
+ bool IsValid() const { return (times != nullptr); }
+ //! Try to load the file times from @a fileName and @return IsValid()
+ bool Load(std::string const& fileName);
+ //! Stores the file times at @a fileName (if IsValid())
+ bool Store(std::string const& fileName) const;
+
+ //! Copies the file times of @a fromFile to @a toFile
+ static bool Copy(std::string const& fromFile, std::string const& toFile);
+
+private:
+#ifdef _WIN32
+ class WindowsHandle;
+#endif
+ class Times;
+ std::unique_ptr<Times> times;
+};
+
+#endif
diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx
index 425546a83..e5908028f 100644
--- a/Source/cmFindBase.cxx
+++ b/Source/cmFindBase.cxx
@@ -4,12 +4,12 @@
#include <deque>
#include <iostream>
-#include <iterator>
#include <map>
#include <stddef.h>
#include "cmAlgorithms.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmSearchPath.h"
#include "cmState.h"
#include "cmStateTypes.h"
@@ -146,8 +146,7 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
std::vector<std::string> shortArgs = this->Names;
this->Names.clear(); // clear out any values in Names
this->Names.push_back(shortArgs[0]);
- this->UserGuessArgs.insert(this->UserGuessArgs.end(),
- shortArgs.begin() + 1, shortArgs.end());
+ cmAppend(this->UserGuessArgs, shortArgs.begin() + 1, shortArgs.end());
}
this->ExpandPaths();
@@ -205,11 +204,9 @@ void cmFindBase::FillPackageRootPath()
cmSearchPath& paths = this->LabeledPaths[PathLabel::PackageRoot];
// Add the PACKAGE_ROOT_PATH from each enclosing find_package call.
- for (std::deque<std::vector<std::string>>::const_reverse_iterator pkgPaths =
- this->Makefile->FindPackageRootPathStack.rbegin();
- pkgPaths != this->Makefile->FindPackageRootPathStack.rend();
- ++pkgPaths) {
- paths.AddPrefixPaths(*pkgPaths);
+ for (std::vector<std::string> const& pkgPaths :
+ cmReverseRange(this->Makefile->FindPackageRootPathStack)) {
+ paths.AddPrefixPaths(pkgPaths);
}
paths.AddSuffixes(this->SearchPathSuffixes);
diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx
index 78be64e09..954558f4d 100644
--- a/Source/cmFindCommon.cxx
+++ b/Source/cmFindCommon.cxx
@@ -6,6 +6,7 @@
#include <string.h>
#include <utility>
+#include "cmAlgorithms.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
@@ -221,7 +222,7 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths)
// If searching both rooted and unrooted paths add the original
// paths again.
if (this->FindRootPathMode == RootPathModeBoth) {
- paths.insert(paths.end(), unrootedPaths.begin(), unrootedPaths.end());
+ cmAppend(paths, unrootedPaths);
}
}
@@ -310,7 +311,7 @@ void cmFindCommon::AddPathSuffix(std::string const& arg)
void AddTrailingSlash(std::string& s)
{
- if (!s.empty() && *s.rbegin() != '/') {
+ if (!s.empty() && s.back() != '/') {
s += '/';
}
}
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index c2e0712ff..1d4a8edd6 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -23,6 +23,7 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmSearchPath.h"
#include "cmState.h"
#include "cmStateTypes.h"
@@ -466,7 +467,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args,
// Allocate a PACKAGE_ROOT_PATH for the current find_package call.
this->Makefile->FindPackageRootPathStack.emplace_back();
std::vector<std::string>& rootPaths =
- *this->Makefile->FindPackageRootPathStack.rbegin();
+ this->Makefile->FindPackageRootPathStack.back();
// Add root paths from <PackageName>_ROOT CMake and environment variables,
// subject to CMP0074.
@@ -497,57 +498,85 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args,
this->SetModuleVariables(components);
// See if there is a Find<PackageName>.cmake module.
- if (this->UseFindModules) {
- bool foundModule = false;
- if (!this->FindModule(foundModule)) {
- this->AppendSuccessInformation();
- return false;
+ bool loadedPackage = false;
+ if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_PREFER_CONFIG")) {
+ if (this->UseConfigFiles && this->FindPackageUsingConfigMode()) {
+ loadedPackage = true;
+ } else {
+ if (this->FindPackageUsingModuleMode()) {
+ loadedPackage = true;
+ } else {
+ // The package was not loaded. Report errors.
+ HandlePackageMode(HandlePackageModeType::Module);
+ }
}
- if (foundModule) {
- this->AppendSuccessInformation();
- return true;
+ } else {
+ if (this->UseFindModules && this->FindPackageUsingModuleMode()) {
+ loadedPackage = true;
+ } else {
+ // Handle CMAKE_FIND_PACKAGE_WARN_NO_MODULE (warn when CONFIG mode is
+ // implicitly assumed)
+ if (this->UseFindModules && this->UseConfigFiles &&
+ this->Makefile->IsOn("CMAKE_FIND_PACKAGE_WARN_NO_MODULE")) {
+ std::ostringstream aw;
+ if (this->RequiredCMakeVersion >= CMake_VERSION_ENCODE(2, 8, 8)) {
+ aw << "find_package called without either MODULE or CONFIG option "
+ "and "
+ "no Find"
+ << this->Name
+ << ".cmake module is in CMAKE_MODULE_PATH. "
+ "Add MODULE to exclusively request Module mode and fail if "
+ "Find"
+ << this->Name
+ << ".cmake is missing. "
+ "Add CONFIG to exclusively request Config mode and search for "
+ "a "
+ "package configuration file provided by "
+ << this->Name << " (" << this->Name << "Config.cmake or "
+ << cmSystemTools::LowerCase(this->Name) << "-config.cmake). ";
+ } else {
+ aw << "find_package called without NO_MODULE option and no "
+ "Find"
+ << this->Name
+ << ".cmake module is in CMAKE_MODULE_PATH. "
+ "Add NO_MODULE to exclusively request Config mode and search "
+ "for a "
+ "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.";
+ }
+ aw << "\n"
+ "(Variable CMAKE_FIND_PACKAGE_WARN_NO_MODULE enabled this "
+ "warning.)";
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, aw.str());
+ }
+
+ if (this->FindPackageUsingConfigMode()) {
+ loadedPackage = true;
+ }
}
}
- if (this->UseFindModules && this->UseConfigFiles &&
- this->Makefile->IsOn("CMAKE_FIND_PACKAGE_WARN_NO_MODULE")) {
- std::ostringstream aw;
- if (this->RequiredCMakeVersion >= CMake_VERSION_ENCODE(2, 8, 8)) {
- aw << "find_package called without either MODULE or CONFIG option and "
- "no Find"
- << this->Name
- << ".cmake module is in CMAKE_MODULE_PATH. "
- "Add MODULE to exclusively request Module mode and fail if "
- "Find"
- << this->Name
- << ".cmake is missing. "
- "Add CONFIG to exclusively request Config mode and search for a "
- "package configuration file provided by "
- << this->Name << " (" << this->Name << "Config.cmake or "
- << cmSystemTools::LowerCase(this->Name) << "-config.cmake). ";
- } else {
- aw
- << "find_package called without NO_MODULE option and no "
- "Find"
- << this->Name
- << ".cmake module is in CMAKE_MODULE_PATH. "
- "Add NO_MODULE to exclusively request Config mode and search for a "
- "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.";
- }
- aw << "\n"
- "(Variable CMAKE_FIND_PACKAGE_WARN_NO_MODULE enabled this warning.)";
- this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, aw.str());
- }
-
- // No find module. Assume the project has a CMake config file. Use
- // a <PackageName>_DIR cache variable to locate it.
+ this->AppendSuccessInformation();
+ return loadedPackage;
+}
+
+bool cmFindPackageCommand::FindPackageUsingModuleMode()
+{
+ bool foundModule = false;
+ if (!this->FindModule(foundModule)) {
+ return false;
+ }
+ return foundModule;
+}
+
+bool cmFindPackageCommand::FindPackageUsingConfigMode()
+{
this->Variable = this->Name;
this->Variable += "_DIR";
@@ -579,9 +608,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args,
this->IgnoredPaths.insert(ignored.begin(), ignored.end());
// Find and load the package.
- bool result = this->HandlePackageMode();
- this->AppendSuccessInformation();
- return result;
+ return this->HandlePackageMode(HandlePackageModeType::Config);
}
void cmFindPackageCommand::SetModuleVariables(const std::string& components)
@@ -700,7 +727,8 @@ bool cmFindPackageCommand::FindModule(bool& found)
return true;
}
-bool cmFindPackageCommand::HandlePackageMode()
+bool cmFindPackageCommand::HandlePackageMode(
+ HandlePackageModeType handlePackageModeType)
{
this->ConsideredConfigs.clear();
@@ -795,6 +823,13 @@ bool cmFindPackageCommand::HandlePackageMode()
}
}
+ if (this->UseFindModules && !found &&
+ handlePackageModeType == HandlePackageModeType::Config &&
+ this->Makefile->IsOn("CMAKE_FIND_PACKAGE_PREFER_CONFIG")) {
+ // Config mode failed. Allow Module case.
+ result = false;
+ }
+
// package not found
if (result && !found) {
// warn if package required or neither quiet nor in config mode
@@ -827,10 +862,10 @@ bool cmFindPackageCommand::HandlePackageMode()
<< " requested version \"" << this->Version << "\".\n"
<< "The following configuration files were considered but not "
"accepted:\n";
- for (std::vector<ConfigFileInfo>::const_iterator i =
- this->ConsideredConfigs.begin();
- i != duplicate_end; ++i) {
- e << " " << i->filename << ", version: " << i->version << "\n";
+
+ for (ConfigFileInfo const& info :
+ cmMakeRange(this->ConsideredConfigs.cbegin(), duplicate_end)) {
+ e << " " << info.filename << ", version: " << info.version << "\n";
}
} else {
std::string requestedVersionString;
@@ -911,7 +946,7 @@ bool cmFindPackageCommand::HandlePackageMode()
std::ostringstream aw;
aw << "Could NOT find " << this->Name << " (missing: " << this->Name
<< "_DIR)";
- this->Makefile->DisplayStatus(aw.str().c_str(), -1);
+ this->Makefile->DisplayStatus(aw.str(), -1);
}
}
@@ -1372,6 +1407,9 @@ public:
cmSystemTools::RemoveFile(this->File);
}
}
+ cmFindPackageCommandHoldFile(const cmFindPackageCommandHoldFile&) = delete;
+ cmFindPackageCommandHoldFile& operator=(
+ const cmFindPackageCommandHoldFile&) = delete;
void Release() { this->File = nullptr; }
};
diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h
index a11d25304..316ca0f3d 100644
--- a/Source/cmFindPackageCommand.h
+++ b/Source/cmFindPackageCommand.h
@@ -90,6 +90,9 @@ private:
static PathLabel SystemRegistry;
};
+ bool FindPackageUsingModuleMode();
+ bool FindPackageUsingConfigMode();
+
// Add additional search path labels and groups not present in the
// parent class
void AppendSearchPathGroups();
@@ -100,7 +103,14 @@ private:
bool FindModule(bool& found);
void AddFindDefinition(const std::string& var, const char* val);
void RestoreFindDefinitions();
- bool HandlePackageMode();
+
+ enum /*class*/ HandlePackageModeType
+ {
+ Module,
+ Config
+ };
+ bool HandlePackageMode(HandlePackageModeType type);
+
bool FindConfig();
bool FindPrefixedConfig();
bool FindFrameworkConfig();
diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx
index e359deff9..08003eb71 100644
--- a/Source/cmForEachCommand.cxx
+++ b/Source/cmForEachCommand.cxx
@@ -11,6 +11,7 @@
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
cmForEachFunctionBlocker::cmForEachFunctionBlocker(cmMakefile* mf)
@@ -48,12 +49,10 @@ bool cmForEachFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
if (mf.GetDefinition(this->Args[0])) {
oldDef = mf.GetDefinition(this->Args[0]);
}
- std::vector<std::string>::const_iterator j = this->Args.begin();
- ++j;
- for (; j != this->Args.end(); ++j) {
+ for (std::string const& arg : cmMakeRange(this->Args).advance(1)) {
// set the variable to the loop value
- mf.AddDefinition(this->Args[0], j->c_str());
+ mf.AddDefinition(this->Args[0], arg.c_str());
// Invoke all the functions that were collected in the block.
cmExecutionStatus status;
for (cmListFileFunction const& func : this->Functions) {
diff --git a/Source/cmFortranParser.h b/Source/cmFortranParser.h
index 076234035..6a33be571 100644
--- a/Source/cmFortranParser.h
+++ b/Source/cmFortranParser.h
@@ -141,6 +141,9 @@ struct cmFortranParser_s
std::set<std::string> defines, cmFortranSourceInfo& info);
~cmFortranParser_s();
+ cmFortranParser_s(const cmFortranParser_s&) = delete;
+ cmFortranParser_s& operator=(const cmFortranParser_s&) = delete;
+
bool FindIncludeFile(const char* dir, const char* includeName,
std::string& fileName);
diff --git a/Source/cmFortranParserImpl.cxx b/Source/cmFortranParserImpl.cxx
index 18e3c107d..e8b1da83c 100644
--- a/Source/cmFortranParserImpl.cxx
+++ b/Source/cmFortranParserImpl.cxx
@@ -79,7 +79,13 @@ std::string cmFortranParser_s::ModName(std::string const& mod_name) const
std::string cmFortranParser_s::SModName(std::string const& mod_name,
std::string const& sub_name) const
{
- return mod_name + this->Compiler.SModSep + sub_name + this->Compiler.SModExt;
+ std::string const& SModExt =
+ this->Compiler.SModExt.empty() ? ".mod" : this->Compiler.SModExt;
+ // An empty separator means that the compiler does not use a prefix.
+ if (this->Compiler.SModSep.empty()) {
+ return sub_name + SModExt;
+ }
+ return mod_name + this->Compiler.SModSep + sub_name + SModExt;
}
bool cmFortranParser_FilePush(cmFortranParser* parser, const char* fname)
diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx
index 264a3385c..9067a5f64 100644
--- a/Source/cmFunctionCommand.cxx
+++ b/Source/cmFunctionCommand.cxx
@@ -8,6 +8,7 @@
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmState.h"
// define the class for function commands
@@ -176,7 +177,7 @@ bool cmFunctionCommand::InitialPass(std::vector<std::string> const& args,
// create a function blocker
cmFunctionFunctionBlocker* f = new cmFunctionFunctionBlocker();
- f->Args.insert(f->Args.end(), args.begin(), args.end());
+ cmAppend(f->Args, args);
this->Makefile->AddFunctionBlocker(f);
return true;
}
diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx
index 4fe15874d..2f47788f8 100644
--- a/Source/cmGeneratedFileStream.cxx
+++ b/Source/cmGeneratedFileStream.cxx
@@ -29,8 +29,7 @@ cmGeneratedFileStream::cmGeneratedFileStream(std::string const& name,
{
// Check if the file opened.
if (!*this && !quiet) {
- cmSystemTools::Error("Cannot open file for write: ",
- this->TempName.c_str());
+ cmSystemTools::Error("Cannot open file for write: " + this->TempName);
cmSystemTools::ReportLastSystemError("");
}
#ifdef CMAKE_BUILD_WITH_CMAKE
@@ -68,8 +67,7 @@ cmGeneratedFileStream& cmGeneratedFileStream::Open(std::string const& name,
// Check if the file opened.
if (!*this && !quiet) {
- cmSystemTools::Error("Cannot open file for write: ",
- this->TempName.c_str());
+ cmSystemTools::Error("Cannot open file for write: " + this->TempName);
cmSystemTools::ReportLastSystemError("");
}
return *this;
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
index f9a6d6454..744201899 100644
--- a/Source/cmGeneratorExpressionEvaluator.cxx
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -34,20 +34,16 @@ std::string GeneratorExpressionContent::ProcessArbitraryContent(
std::vector<cmGeneratorExpressionEvaluator*>>::const_iterator pend =
this->ParamChildren.end();
for (; pit != pend; ++pit) {
- std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
- pit->begin();
- const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
- pit->end();
- for (; it != end; ++it) {
+ for (cmGeneratorExpressionEvaluator* pExprEval : *pit) {
if (node->RequiresLiteralInput()) {
- if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text) {
+ if (pExprEval->GetType() != cmGeneratorExpressionEvaluator::Text) {
reportError(context, this->GetOriginalExpression(),
"$<" + identifier +
"> expression requires literal input.");
return std::string();
}
}
- result += (*it)->Evaluate(context, dagChecker);
+ result += pExprEval->Evaluate(context, dagChecker);
if (context->HadError) {
return std::string();
}
@@ -70,12 +66,9 @@ std::string GeneratorExpressionContent::Evaluate(
{
std::string identifier;
{
- std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
- this->IdentifierChildren.begin();
- const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
- this->IdentifierChildren.end();
- for (; it != end; ++it) {
- identifier += (*it)->Evaluate(context, dagChecker);
+ for (cmGeneratorExpressionEvaluator* pExprEval :
+ this->IdentifierChildren) {
+ identifier += pExprEval->Evaluate(context, dagChecker);
if (context->HadError) {
return std::string();
}
@@ -138,12 +131,8 @@ std::string GeneratorExpressionContent::EvaluateParameters(
return std::string();
}
std::string parameter;
- std::vector<cmGeneratorExpressionEvaluator*>::const_iterator it =
- pit->begin();
- const std::vector<cmGeneratorExpressionEvaluator*>::const_iterator end =
- pit->end();
- for (; it != end; ++it) {
- parameter += (*it)->Evaluate(context, dagChecker);
+ for (cmGeneratorExpressionEvaluator* pExprEval : *pit) {
+ parameter += pExprEval->Evaluate(context, dagChecker);
if (context->HadError) {
return std::string();
}
@@ -177,9 +166,13 @@ std::string GeneratorExpressionContent::EvaluateParameters(
reportError(context, this->GetOriginalExpression(),
"$<" + identifier +
"> expression requires at least one parameter.");
- }
- if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters &&
- parameters.size() > 1) {
+ } else if (numExpected == cmGeneratorExpressionNode::TwoOrMoreParameters &&
+ parameters.size() < 2) {
+ reportError(context, this->GetOriginalExpression(),
+ "$<" + identifier +
+ "> expression requires at least two parameters.");
+ } else if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters &&
+ parameters.size() > 1) {
reportError(context, this->GetOriginalExpression(),
"$<" + identifier +
"> expression requires one or zero parameters.");
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 70c80c90d..a60c75cd9 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -15,16 +15,23 @@
#include "cmMessageType.h"
#include "cmOutputConverter.h"
#include "cmPolicies.h"
+#include "cmRange.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
+#include "cm_static_string_view.hxx"
+#include "cm_string_view.hxx"
#include "cmake.h"
#include "cmsys/RegularExpression.hxx"
#include "cmsys/String.h"
+
#include <algorithm>
#include <assert.h>
#include <errno.h>
+#include <iterator>
#include <map>
#include <memory> // IWYU pragma: keep
#include <set>
@@ -92,38 +99,42 @@ static const struct OneNode buildInterfaceNode;
static const struct ZeroNode installInterfaceNode;
-#define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \
- static const struct OP##Node : public cmGeneratorExpressionNode \
- { \
- OP##Node() {} /* NOLINT(modernize-use-equals-default) */ \
- virtual int NumExpectedParameters() const { return OneOrMoreParameters; } \
- \
- std::string Evaluate(const std::vector<std::string>& parameters, \
- cmGeneratorExpressionContext* context, \
- const GeneratorExpressionContent* content, \
- cmGeneratorExpressionDAGChecker*) const \
- { \
- std::vector<std::string>::const_iterator it = parameters.begin(); \
- const std::vector<std::string>::const_iterator end = parameters.end(); \
- for (; it != end; ++it) { \
- if (*it == #FAILURE_VALUE) { \
- return #FAILURE_VALUE; \
- } \
- if (*it != #SUCCESS_VALUE) { \
- reportError(context, content->GetOriginalExpression(), \
- "Parameters to $<" #OP \
- "> must resolve to either '0' or '1'."); \
- return std::string(); \
- } \
- } \
- return #SUCCESS_VALUE; \
- } \
- } OPNAME;
-
-BOOLEAN_OP_NODE(andNode, AND, 1, 0)
-BOOLEAN_OP_NODE(orNode, OR, 0, 1)
-
-#undef BOOLEAN_OP_NODE
+struct BooleanOpNode : public cmGeneratorExpressionNode
+{
+ BooleanOpNode(const char* op_, const char* successVal_,
+ const char* failureVal_)
+ : op(op_)
+ , successVal(successVal_)
+ , failureVal(failureVal_)
+ {
+ }
+
+ int NumExpectedParameters() const override { return OneOrMoreParameters; }
+
+ std::string Evaluate(const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker*) const override
+ {
+ for (std::string const& param : parameters) {
+ if (param == this->failureVal) {
+ return this->failureVal;
+ }
+ if (param != this->successVal) {
+ std::ostringstream e;
+ e << "Parameters to $<" << this->op;
+ e << "> must resolve to either '0' or '1'.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return std::string();
+ }
+ }
+ return this->successVal;
+ }
+
+ const char *const op, *const successVal, *const failureVal;
+};
+
+static const BooleanOpNode andNode("AND", "1", "0"), orNode("OR", "0", "1");
static const struct NotNode : public cmGeneratorExpressionNode
{
@@ -135,13 +146,13 @@ static const struct NotNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- if (*parameters.begin() != "0" && *parameters.begin() != "1") {
+ if (parameters.front() != "0" && parameters.front() != "1") {
reportError(
context, content->GetOriginalExpression(),
"$<NOT> parameter must resolve to exactly one '0' or '1' value.");
return std::string();
}
- return *parameters.begin() == "0" ? "1" : "0";
+ return parameters.front() == "0" ? "1" : "0";
}
} notNode;
@@ -157,7 +168,7 @@ static const struct BoolNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* /*content*/,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- return !cmSystemTools::IsOff(*parameters.begin()) ? "1" : "0";
+ return !cmSystemTools::IsOff(parameters.front()) ? "1" : "0";
}
} boolNode;
@@ -194,7 +205,7 @@ static const struct StrEqualNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* /*content*/,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- return *parameters.begin() == parameters[1] ? "1" : "0";
+ return parameters.front() == parameters[1] ? "1" : "0";
}
} strEqualNode;
@@ -210,69 +221,44 @@ static const struct EqualNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- char* pEnd;
-
- int base = 0;
- bool flipSign = false;
-
- const char* lhs = parameters[0].c_str();
- if (cmHasLiteralPrefix(lhs, "0b") || cmHasLiteralPrefix(lhs, "0B")) {
- base = 2;
- lhs += 2;
- }
- if (cmHasLiteralPrefix(lhs, "-0b") || cmHasLiteralPrefix(lhs, "-0B")) {
- base = 2;
- lhs += 3;
- flipSign = true;
- }
- if (cmHasLiteralPrefix(lhs, "+0b") || cmHasLiteralPrefix(lhs, "+0B")) {
- base = 2;
- lhs += 3;
- }
-
- long lnum = strtol(lhs, &pEnd, base);
- if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) {
- reportError(context, content->GetOriginalExpression(),
- "$<EQUAL> parameter " + parameters[0] +
- " is not a valid integer.");
- return std::string();
- }
-
- if (flipSign) {
- lnum = -lnum;
+ long numbers[2];
+ for (int i = 0; i < 2; ++i) {
+ if (!ParameterToLong(parameters[i].c_str(), &numbers[i])) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<EQUAL> parameter " + parameters[i] +
+ " is not a valid integer.");
+ return {};
+ }
}
+ return numbers[0] == numbers[1] ? "1" : "0";
+ }
- base = 0;
- flipSign = false;
+ static bool ParameterToLong(const char* param, long* outResult)
+ {
+ const char isNegative = param[0] == '-';
- const char* rhs = parameters[1].c_str();
- if (cmHasLiteralPrefix(rhs, "0b") || cmHasLiteralPrefix(rhs, "0B")) {
- base = 2;
- rhs += 2;
- }
- if (cmHasLiteralPrefix(rhs, "-0b") || cmHasLiteralPrefix(rhs, "-0B")) {
+ int base = 0;
+ if (cmHasLiteralPrefix(param, "0b") || cmHasLiteralPrefix(param, "0B")) {
base = 2;
- rhs += 3;
- flipSign = true;
- }
- if (cmHasLiteralPrefix(rhs, "+0b") || cmHasLiteralPrefix(rhs, "+0B")) {
+ param += 2;
+ } else if (cmHasLiteralPrefix(param, "-0b") ||
+ cmHasLiteralPrefix(param, "-0B") ||
+ cmHasLiteralPrefix(param, "+0b") ||
+ cmHasLiteralPrefix(param, "+0B")) {
base = 2;
- rhs += 3;
+ param += 3;
}
- long rnum = strtol(rhs, &pEnd, base);
- if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) {
- reportError(context, content->GetOriginalExpression(),
- "$<EQUAL> parameter " + parameters[1] +
- " is not a valid integer.");
- return std::string();
+ char* pEnd;
+ long result = strtol(param, &pEnd, base);
+ if (pEnd == param || *pEnd != '\0' || errno == ERANGE) {
+ return false;
}
-
- if (flipSign) {
- rnum = -rnum;
+ if (isNegative && result > 0) {
+ result *= -1;
}
-
- return lnum == rnum ? "1" : "0";
+ *outResult = result;
+ return true;
}
} equalNode;
@@ -326,6 +312,79 @@ static const struct InListNode : public cmGeneratorExpressionNode
}
} inListNode;
+static const struct FilterNode : public cmGeneratorExpressionNode
+{
+ FilterNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 3; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ if (parameters.size() != 3) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<FILTER:...> expression requires three parameters");
+ return {};
+ }
+
+ if (parameters[1] != "INCLUDE" && parameters[1] != "EXCLUDE") {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<FILTER:...> second parameter must be either INCLUDE or EXCLUDE");
+ return {};
+ }
+
+ const bool exclude = parameters[1] == "EXCLUDE";
+
+ cmsys::RegularExpression re;
+ if (!re.compile(parameters[2])) {
+ reportError(context, content->GetOriginalExpression(),
+ "$<FILTER:...> failed to compile regex");
+ return {};
+ }
+
+ std::vector<std::string> values, result;
+ cmSystemTools::ExpandListArgument(parameters.front(), values, true);
+
+ std::copy_if(values.cbegin(), values.cend(), std::back_inserter(result),
+ [&re, exclude](std::string const& input) {
+ return exclude ^ re.find(input);
+ });
+ return cmJoin(cmMakeRange(result.cbegin(), result.cend()), ";");
+ }
+} filterNode;
+
+static const struct RemoveDuplicatesNode : public cmGeneratorExpressionNode
+{
+ RemoveDuplicatesNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ {
+ if (parameters.size() != 1) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<REMOVE_DUPLICATES:...> expression requires one parameter");
+ }
+
+ std::vector<std::string> values;
+ cmSystemTools::ExpandListArgument(parameters.front(), values, true);
+
+ auto valuesEnd = cmRemoveDuplicates(values);
+ auto valuesBegin = values.cbegin();
+ return cmJoin(cmMakeRange(valuesBegin, valuesEnd), ";");
+ }
+
+} removeDuplicatesNode;
+
static const struct TargetExistsNode : public cmGeneratorExpressionNode
{
TargetExistsNode() {} // NOLINT(modernize-use-equals-default)
@@ -546,9 +605,10 @@ static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode
}
} makeCIdentifierNode;
-static const struct Angle_RNode : public cmGeneratorExpressionNode
+template <char C>
+struct CharacterNode : public cmGeneratorExpressionNode
{
- Angle_RNode() {} // NOLINT(modernize-use-equals-default)
+ CharacterNode() {} // NOLINT(modernize-use-equals-default)
int NumExpectedParameters() const override { return 0; }
@@ -558,47 +618,39 @@ static const struct Angle_RNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* /*content*/,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- return ">";
+ return { C };
}
-} angle_rNode;
+};
+static const CharacterNode<'>'> angle_rNode;
+static const CharacterNode<','> commaNode;
+static const CharacterNode<';'> semicolonNode;
-static const struct CommaNode : public cmGeneratorExpressionNode
+struct CompilerIdNode : public cmGeneratorExpressionNode
{
- CommaNode() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return 0; }
-
- std::string Evaluate(
- const std::vector<std::string>& /*parameters*/,
- cmGeneratorExpressionContext* /*context*/,
- const GeneratorExpressionContent* /*content*/,
- cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ CompilerIdNode(const char* compilerLang)
+ : CompilerLanguage(compilerLang)
{
- return ",";
}
-} commaNode;
-static const struct SemicolonNode : public cmGeneratorExpressionNode
-{
- SemicolonNode() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return 0; }
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
std::string Evaluate(
- const std::vector<std::string>& /*parameters*/,
- cmGeneratorExpressionContext* /*context*/,
- const GeneratorExpressionContent* /*content*/,
- cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
{
- return ";";
+ if (!context->HeadTarget) {
+ std::ostringstream e;
+ e << "$<" << this->CompilerLanguage
+ << "_COMPILER_ID> may only be used with binary targets. It may "
+ "not be used with add_custom_command or add_custom_target.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return {};
+ }
+ return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
+ this->CompilerLanguage);
}
-} semicolonNode;
-
-struct CompilerIdNode : public cmGeneratorExpressionNode
-{
- CompilerIdNode() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return OneOrZeroParameters; }
std::string EvaluateWithLanguage(const std::vector<std::string>& parameters,
cmGeneratorExpressionContext* context,
@@ -612,89 +664,58 @@ struct CompilerIdNode : public cmGeneratorExpressionNode
if (parameters.empty()) {
return compilerId;
}
- static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$");
- if (!compilerIdValidator.find(*parameters.begin())) {
- reportError(context, content->GetOriginalExpression(),
- "Expression syntax not recognized.");
- return std::string();
- }
if (compilerId.empty()) {
return parameters.front().empty() ? "1" : "0";
}
+ static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$");
- if (strcmp(parameters.begin()->c_str(), compilerId.c_str()) == 0) {
- return "1";
- }
+ for (auto& param : parameters) {
- if (cmsysString_strcasecmp(parameters.begin()->c_str(),
- compilerId.c_str()) == 0) {
- switch (context->LG->GetPolicyStatus(cmPolicies::CMP0044)) {
- case cmPolicies::WARN: {
- std::ostringstream e;
- e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0044);
- context->LG->GetCMakeInstance()->IssueMessage(
- MessageType::AUTHOR_WARNING, e.str(), context->Backtrace);
- CM_FALLTHROUGH;
+ if (!compilerIdValidator.find(param)) {
+ reportError(context, content->GetOriginalExpression(),
+ "Expression syntax not recognized.");
+ return std::string();
+ }
+
+ if (strcmp(param.c_str(), compilerId.c_str()) == 0) {
+ return "1";
+ }
+
+ if (cmsysString_strcasecmp(param.c_str(), compilerId.c_str()) == 0) {
+ switch (context->LG->GetPolicyStatus(cmPolicies::CMP0044)) {
+ case cmPolicies::WARN: {
+ std::ostringstream e;
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0044);
+ context->LG->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING, e.str(), context->Backtrace);
+ CM_FALLTHROUGH;
+ }
+ case cmPolicies::OLD:
+ return "1";
+ case cmPolicies::NEW:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ break;
}
- case cmPolicies::OLD:
- return "1";
- case cmPolicies::NEW:
- case cmPolicies::REQUIRED_ALWAYS:
- case cmPolicies::REQUIRED_IF_USED:
- break;
}
}
return "0";
}
+
+ const char* const CompilerLanguage;
};
-static const struct CCompilerIdNode : public CompilerIdNode
-{
- CCompilerIdNode() {} // NOLINT(modernize-use-equals-default)
+static const CompilerIdNode cCompilerIdNode("C"), cxxCompilerIdNode("CXX"),
+ cudaCompilerIdNode("CUDA"), fortranCompilerIdNode("Fortran");
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* context,
- const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* dagChecker) const override
- {
- if (!context->HeadTarget) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<C_COMPILER_ID> may only be used with binary targets. It may "
- "not be used with add_custom_command or add_custom_target.");
- return std::string();
- }
- return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
- "C");
- }
-} cCompilerIdNode;
-
-static const struct CXXCompilerIdNode : public CompilerIdNode
+struct CompilerVersionNode : public cmGeneratorExpressionNode
{
- CXXCompilerIdNode() {} // NOLINT(modernize-use-equals-default)
-
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* context,
- const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* dagChecker) const override
+ CompilerVersionNode(const char* compilerLang)
+ : CompilerLanguage(compilerLang)
{
- if (!context->HeadTarget) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<CXX_COMPILER_ID> may only be used with binary targets. It may "
- "not be used with add_custom_command or add_custom_target.");
- return std::string();
- }
- return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
- "CXX");
}
-} cxxCompilerIdNode;
-static const struct FortranCompilerIdNode : public CompilerIdNode
-{
- FortranCompilerIdNode() {} // NOLINT(modernize-use-equals-default)
+ int NumExpectedParameters() const override { return OneOrZeroParameters; }
std::string Evaluate(
const std::vector<std::string>& parameters,
@@ -703,22 +724,16 @@ static const struct FortranCompilerIdNode : public CompilerIdNode
cmGeneratorExpressionDAGChecker* dagChecker) const override
{
if (!context->HeadTarget) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<Fortran_COMPILER_ID> may only be used with binary targets. It may "
- "not be used with add_custom_command or add_custom_target.");
- return std::string();
+ std::ostringstream e;
+ e << "$<" << this->CompilerLanguage
+ << "_COMPILER_VERSION> may only be used with binary targets. It "
+ "may not be used with add_custom_command or add_custom_target.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ return {};
}
return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
- "Fortran");
+ this->CompilerLanguage);
}
-} fortranCompilerIdNode;
-
-struct CompilerVersionNode : public cmGeneratorExpressionNode
-{
- CompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return OneOrZeroParameters; }
std::string EvaluateWithLanguage(const std::vector<std::string>& parameters,
cmGeneratorExpressionContext* context,
@@ -734,94 +749,34 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode
}
static cmsys::RegularExpression compilerIdValidator("^[0-9\\.]*$");
- if (!compilerIdValidator.find(*parameters.begin())) {
+ if (!compilerIdValidator.find(parameters.front())) {
reportError(context, content->GetOriginalExpression(),
"Expression syntax not recognized.");
- return std::string();
+ return {};
}
if (compilerVersion.empty()) {
return parameters.front().empty() ? "1" : "0";
}
return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
- parameters.begin()->c_str(),
+ parameters.front().c_str(),
compilerVersion.c_str())
? "1"
: "0";
}
-};
-
-static const struct CCompilerVersionNode : public CompilerVersionNode
-{
- CCompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
-
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* context,
- const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* dagChecker) const override
- {
- if (!context->HeadTarget) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<C_COMPILER_VERSION> may only be used with binary targets. It "
- "may not be used with add_custom_command or add_custom_target.");
- return std::string();
- }
- return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
- "C");
- }
-} cCompilerVersionNode;
-
-static const struct CxxCompilerVersionNode : public CompilerVersionNode
-{
- CxxCompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
-
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* context,
- const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* dagChecker) const override
- {
- if (!context->HeadTarget) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<CXX_COMPILER_VERSION> may only be used with binary targets. It "
- "may not be used with add_custom_command or add_custom_target.");
- return std::string();
- }
- return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
- "CXX");
- }
-} cxxCompilerVersionNode;
-static const struct FortranCompilerVersionNode : public CompilerVersionNode
-{
- FortranCompilerVersionNode() {} // NOLINT(modernize-use-equals-default)
+ const char* const CompilerLanguage;
+};
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* context,
- const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* dagChecker) const override
- {
- if (!context->HeadTarget) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<Fortran_COMPILER_VERSION> may only be used with binary targets. "
- "It may not be used with add_custom_command or add_custom_target.");
- return std::string();
- }
- return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
- "Fortran");
- }
-} fortranCompilerVersionNode;
+static const CompilerVersionNode cCompilerVersionNode("C"),
+ cxxCompilerVersionNode("CXX"), cudaCompilerVersionNode("CUDA"),
+ fortranCompilerVersionNode("Fortran");
struct PlatformIdNode : public cmGeneratorExpressionNode
{
PlatformIdNode() {} // NOLINT(modernize-use-equals-default)
- int NumExpectedParameters() const override { return OneOrZeroParameters; }
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
std::string Evaluate(
const std::vector<std::string>& parameters,
@@ -839,76 +794,19 @@ struct PlatformIdNode : public cmGeneratorExpressionNode
return parameters.front().empty() ? "1" : "0";
}
- if (*parameters.begin() == platformId) {
- return "1";
+ for (auto& param : parameters) {
+ if (param == platformId) {
+ return "1";
+ }
}
return "0";
}
} platformIdNode;
-static const struct VersionGreaterNode : public cmGeneratorExpressionNode
-{
- VersionGreaterNode() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return 2; }
-
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* /*context*/,
- const GeneratorExpressionContent* /*content*/,
- cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
- {
- return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER,
- parameters.front().c_str(),
- parameters[1].c_str())
- ? "1"
- : "0";
- }
-} versionGreaterNode;
-
-static const struct VersionGreaterEqNode : public cmGeneratorExpressionNode
-{
- VersionGreaterEqNode() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return 2; }
-
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* /*context*/,
- const GeneratorExpressionContent* /*content*/,
- cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
- {
- return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
- parameters.front().c_str(),
- parameters[1].c_str())
- ? "1"
- : "0";
- }
-} versionGreaterEqNode;
-
-static const struct VersionLessNode : public cmGeneratorExpressionNode
-{
- VersionLessNode() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return 2; }
-
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* /*context*/,
- const GeneratorExpressionContent* /*content*/,
- cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
- {
- return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
- parameters.front().c_str(),
- parameters[1].c_str())
- ? "1"
- : "0";
- }
-} versionLessNode;
-
-static const struct VersionLessEqNode : public cmGeneratorExpressionNode
+template <cmSystemTools::CompareOp Op>
+struct VersionNode : public cmGeneratorExpressionNode
{
- VersionLessEqNode() {} // NOLINT(modernize-use-equals-default)
+ VersionNode() {} // NOLINT(modernize-use-equals-default)
int NumExpectedParameters() const override { return 2; }
@@ -918,33 +816,18 @@ static const struct VersionLessEqNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* /*content*/,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS_EQUAL,
- parameters.front().c_str(),
+ return cmSystemTools::VersionCompare(Op, parameters.front().c_str(),
parameters[1].c_str())
? "1"
: "0";
}
-} versionLessEqNode;
-
-static const struct VersionEqualNode : public cmGeneratorExpressionNode
-{
- VersionEqualNode() {} // NOLINT(modernize-use-equals-default)
+};
- int NumExpectedParameters() const override { return 2; }
-
- std::string Evaluate(
- const std::vector<std::string>& parameters,
- cmGeneratorExpressionContext* /*context*/,
- const GeneratorExpressionContent* /*content*/,
- cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
- {
- return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
- parameters.front().c_str(),
- parameters[1].c_str())
- ? "1"
- : "0";
- }
-} versionEqualNode;
+static const VersionNode<cmSystemTools::OP_GREATER> versionGreaterNode;
+static const VersionNode<cmSystemTools::OP_GREATER_EQUAL> versionGreaterEqNode;
+static const VersionNode<cmSystemTools::OP_LESS> versionLessNode;
+static const VersionNode<cmSystemTools::OP_LESS_EQUAL> versionLessEqNode;
+static const VersionNode<cmSystemTools::OP_EQUAL> versionEqualNode;
static const struct LinkOnlyNode : public cmGeneratorExpressionNode
{
@@ -1001,7 +884,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
return configurationNode.Evaluate(parameters, context, content, nullptr);
}
static cmsys::RegularExpression configValidator("^[A-Za-z0-9_]*$");
- if (!configValidator.find(*parameters.begin())) {
+ if (!configValidator.find(parameters.front())) {
reportError(context, content->GetOriginalExpression(),
"Expression syntax not recognized.");
return std::string();
@@ -1011,7 +894,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
return parameters.front().empty() ? "1" : "0";
}
- if (cmsysString_strcasecmp(parameters.begin()->c_str(),
+ if (cmsysString_strcasecmp(parameters.front().c_str(),
context->Config.c_str()) == 0) {
return "1";
}
@@ -1068,7 +951,7 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
{
CompileLanguageNode() {} // NOLINT(modernize-use-equals-default)
- int NumExpectedParameters() const override { return OneOrZeroParameters; }
+ int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
std::string Evaluate(
const std::vector<std::string>& parameters,
@@ -1099,10 +982,62 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
if (parameters.empty()) {
return context->Language;
}
- return context->Language == parameters.front() ? "1" : "0";
+
+ for (auto& param : parameters) {
+ if (context->Language == param) {
+ return "1";
+ }
+ }
+ return "0";
}
} languageNode;
+static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode
+{
+ CompileLanguageAndIdNode() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return TwoOrMoreParameters; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ if (!context->HeadTarget || context->Language.empty()) {
+ // reportError(context, content->GetOriginalExpression(), "");
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary targets "
+ "to specify include directories, compile definitions, and compile "
+ "options. It may not be used with the add_custom_command, "
+ "add_custom_target, or file(GENERATE) commands.");
+ return std::string();
+ }
+ cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
+ std::string genName = gg->GetName();
+ if (genName.find("Makefiles") == std::string::npos &&
+ genName.find("Ninja") == std::string::npos &&
+ genName.find("Visual Studio") == std::string::npos &&
+ genName.find("Xcode") == std::string::npos &&
+ genName.find("Watcom WMake") == std::string::npos) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<COMPILE_LANG_AND_ID:lang,id> not supported for this generator.");
+ return std::string();
+ }
+
+ const std::string& lang = context->Language;
+ if (lang == parameters.front()) {
+ std::vector<std::string> idParameter((parameters.cbegin() + 1),
+ parameters.cend());
+ return CompilerIdNode{ lang.c_str() }.EvaluateWithLanguage(
+ idParameter, context, content, dagChecker, lang);
+ }
+ return "0";
+ }
+} languageAndIdNode;
+
#define TRANSITIVE_PROPERTY_NAME(PROPERTY) , "INTERFACE_" #PROPERTY
static const char* targetPropertyTransitiveWhitelist[] = {
@@ -1151,73 +1086,54 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
// This node handles errors on parameter count itself.
int NumExpectedParameters() const override { return OneOrMoreParameters; }
+ static const char* GetErrorText(std::string const& targetName,
+ std::string const& propertyName)
+ {
+ static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
+ if (targetName.empty() && propertyName.empty()) {
+ return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
+ "target name and property name.";
+ }
+ if (targetName.empty()) {
+ return "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
+ "target name.";
+ }
+ if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
+ if (!propertyNameValidator.find(propertyName)) {
+ return "Target name and property name not supported.";
+ }
+ return "Target name not supported.";
+ }
+ return nullptr;
+ }
+
std::string Evaluate(
const std::vector<std::string>& parameters,
cmGeneratorExpressionContext* context,
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* dagCheckerParent) const override
{
- if (parameters.size() != 1 && parameters.size() != 2) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<TARGET_PROPERTY:...> expression requires one or two parameters");
- return std::string();
- }
static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
- cmGeneratorTarget const* target = context->HeadTarget;
- std::string propertyName = *parameters.begin();
-
- if (parameters.size() == 1) {
- context->HadHeadSensitiveCondition = true;
- }
- if (!target && parameters.size() == 1) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<TARGET_PROPERTY:prop> may only be used with binary targets. "
- "It may not be used with add_custom_command or add_custom_target. "
- "Specify the target to read a property from using the "
- "$<TARGET_PROPERTY:tgt,prop> signature instead.");
- return std::string();
- }
+ cmGeneratorTarget const* target = nullptr;
+ std::string targetName, propertyName;
if (parameters.size() == 2) {
- if (parameters.begin()->empty() && parameters[1].empty()) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
- "target name and property name.");
- return std::string();
- }
- if (parameters.begin()->empty()) {
- reportError(
- context, content->GetOriginalExpression(),
- "$<TARGET_PROPERTY:tgt,prop> expression requires a non-empty "
- "target name.");
- return std::string();
- }
-
- std::string targetName = parameters.front();
+ targetName = parameters[0];
propertyName = parameters[1];
- if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
- if (!propertyNameValidator.find(propertyName)) {
- ::reportError(context, content->GetOriginalExpression(),
- "Target name and property name not supported.");
- return std::string();
- }
- ::reportError(context, content->GetOriginalExpression(),
- "Target name not supported.");
+
+ if (const char* e = GetErrorText(targetName, propertyName)) {
+ reportError(context, content->GetOriginalExpression(), e);
return std::string();
}
- static const std::string propALIASED_TARGET = "ALIASED_TARGET";
- if (propertyName == propALIASED_TARGET) {
+ if (propertyName == "ALIASED_TARGET"_s) {
if (context->LG->GetMakefile()->IsAlias(targetName)) {
if (cmGeneratorTarget* tgt =
context->LG->FindGeneratorTargetToUse(targetName)) {
return tgt->GetName();
}
}
- return "";
+ return std::string();
}
target = context->LG->FindGeneratorTargetToUse(targetName);
@@ -1228,15 +1144,34 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
return std::string();
}
context->AllTargets.insert(target);
- }
- if (target == context->HeadTarget) {
+ } else if (parameters.size() == 1) {
+ target = context->HeadTarget;
+ propertyName = parameters[0];
+
// Keep track of the properties seen while processing.
// The evaluation of the LINK_LIBRARIES generator expressions
// will check this to ensure that properties have one consistent
// value for all evaluations.
context->SeenTargetProperties.insert(propertyName);
+
+ context->HadHeadSensitiveCondition = true;
+ if (!target) {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<TARGET_PROPERTY:prop> may only be used with binary targets. "
+ "It may not be used with add_custom_command or add_custom_target. "
+ "Specify the target to read a property from using the "
+ "$<TARGET_PROPERTY:tgt,prop> signature instead.");
+ return std::string();
+ }
+ } else {
+ reportError(
+ context, content->GetOriginalExpression(),
+ "$<TARGET_PROPERTY:...> expression requires one or two parameters");
+ return std::string();
}
+
if (propertyName == "SOURCES") {
context->SourceSensitiveTargets.insert(target);
}
@@ -1292,7 +1227,12 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
break;
}
- const char* prop = target->GetProperty(propertyName);
+ std::string prop;
+ bool haveProp = false;
+ if (const char* p = target->GetProperty(propertyName)) {
+ prop = p;
+ haveProp = true;
+ }
if (dagCheckerParent) {
if (dagCheckerParent->EvaluatingGenexExpression() ||
@@ -1312,7 +1252,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
}
#undef TRANSITIVE_PROPERTY_COMPARE
- if (!prop) {
+ if (!haveProp) {
return std::string();
}
} else {
@@ -1368,7 +1308,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
}
}
- if (!prop) {
+ if (!haveProp) {
if (target->IsImported() ||
target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
return linkedTargetsContent;
@@ -1481,10 +1421,16 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
reportError(context, content->GetOriginalExpression(), e.str());
return std::string();
}
- if (gt->GetType() != cmStateEnums::OBJECT_LIBRARY) {
+ cmStateEnums::TargetType type = gt->GetType();
+ if (type != cmStateEnums::EXECUTABLE &&
+ type != cmStateEnums::STATIC_LIBRARY &&
+ type != cmStateEnums::SHARED_LIBRARY &&
+ type != cmStateEnums::MODULE_LIBRARY &&
+ type != cmStateEnums::OBJECT_LIBRARY) {
std::ostringstream e;
e << "Objects of target \"" << tgtName
- << "\" referenced but is not an OBJECT library.";
+ << "\" referenced but is not an allowed library types (EXECUTABLE, "
+ << "STATIC, SHARED, MODULE, OBJECT).";
reportError(context, content->GetOriginalExpression(), e.str());
return std::string();
}
@@ -1950,39 +1896,37 @@ struct TargetFilesystemArtifactResultGetter<ArtifactPathTag>
static std::string Get(const std::string& result) { return result; }
};
-template <typename ArtifactT, typename ComponentT>
-struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
+struct TargetArtifactBase : public cmGeneratorExpressionNode
{
- TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
-
- int NumExpectedParameters() const override { return 1; }
+ TargetArtifactBase() {} // NOLINT(modernize-use-equals-default)
- std::string Evaluate(
+protected:
+ cmGeneratorTarget* GetTarget(
const std::vector<std::string>& parameters,
cmGeneratorExpressionContext* context,
const GeneratorExpressionContent* content,
- cmGeneratorExpressionDAGChecker* dagChecker) const override
+ cmGeneratorExpressionDAGChecker* dagChecker) const
{
// Lookup the referenced target.
- std::string name = *parameters.begin();
+ std::string name = parameters.front();
if (!cmGeneratorExpression::IsValidTargetName(name)) {
::reportError(context, content->GetOriginalExpression(),
"Expression syntax not recognized.");
- return std::string();
+ return nullptr;
}
cmGeneratorTarget* target = context->LG->FindGeneratorTargetToUse(name);
if (!target) {
::reportError(context, content->GetOriginalExpression(),
"No target \"" + name + "\"");
- return std::string();
+ return nullptr;
}
if (target->GetType() >= cmStateEnums::OBJECT_LIBRARY &&
target->GetType() != cmStateEnums::UNKNOWN_LIBRARY) {
::reportError(context, content->GetOriginalExpression(),
"Target \"" + name +
"\" is not an executable or library.");
- return std::string();
+ return nullptr;
}
if (dagChecker &&
(dagChecker->EvaluatingLinkLibraries(target) ||
@@ -1991,6 +1935,29 @@ struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
::reportError(context, content->GetOriginalExpression(),
"Expressions which require the linker language may not "
"be used while evaluating link libraries");
+ return nullptr;
+ }
+
+ return target;
+ }
+};
+
+template <typename ArtifactT, typename ComponentT>
+struct TargetFilesystemArtifact : public TargetArtifactBase
+{
+ TargetFilesystemArtifact() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ cmGeneratorTarget* target =
+ this->GetTarget(parameters, context, content, dagChecker);
+ if (!target) {
return std::string();
}
context->DependTargets.insert(target);
@@ -2037,6 +2004,242 @@ static const TargetFilesystemArtifact<ArtifactBundleContentDirTag,
ArtifactPathTag>
targetBundleContentDirNode;
+//
+// To retrieve base name for various artifacts
+//
+template <typename ArtifactT>
+struct TargetOutputNameArtifactResultGetter
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content);
+};
+
+template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactNameTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* /*unused*/)
+ {
+ return target->GetOutputName(context->Config,
+ cmStateEnums::RuntimeBinaryArtifact) +
+ target->GetFilePostfix(context->Config);
+ }
+};
+
+template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ // The file used to link to the target (.so, .lib, .a).
+ if (!target->IsLinkable()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_LINKER_FILE_BASE_NAME is allowed only for "
+ "libraries and executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+ cmStateEnums::ArtifactType artifact =
+ target->HasImportLibrary(context->Config)
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+ return target->GetOutputName(context->Config, artifact) +
+ target->GetFilePostfix(context->Config);
+ }
+};
+
+template <>
+struct TargetOutputNameArtifactResultGetter<ArtifactPdbTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (target->IsImported()) {
+ ::reportError(
+ context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE_BASE_NAME not allowed for IMPORTED targets.");
+ return std::string();
+ }
+
+ std::string language = target->GetLinkerLanguage(context->Config);
+
+ std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB";
+
+ if (!context->LG->GetMakefile()->IsOn(pdbSupportVar)) {
+ ::reportError(
+ context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE_BASE_NAME is not supported by the target linker.");
+ return std::string();
+ }
+
+ cmStateEnums::TargetType targetType = target->GetType();
+
+ if (targetType != cmStateEnums::SHARED_LIBRARY &&
+ targetType != cmStateEnums::MODULE_LIBRARY &&
+ targetType != cmStateEnums::EXECUTABLE) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_PDB_FILE_BASE_NAME is allowed only for "
+ "targets with linker created artifacts.");
+ return std::string();
+ }
+
+ return target->GetPDBOutputName(context->Config) +
+ target->GetFilePostfix(context->Config);
+ }
+};
+
+template <typename ArtifactT>
+struct TargetFileBaseNameArtifact : public TargetArtifactBase
+{
+ TargetFileBaseNameArtifact() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ cmGeneratorTarget* target =
+ this->GetTarget(parameters, context, content, dagChecker);
+ if (!target) {
+ return std::string();
+ }
+
+ std::string result = TargetOutputNameArtifactResultGetter<ArtifactT>::Get(
+ target, context, content);
+ if (context->HadError) {
+ return std::string();
+ }
+ return result;
+ }
+};
+
+static const TargetFileBaseNameArtifact<ArtifactNameTag>
+ targetFileBaseNameNode;
+static const TargetFileBaseNameArtifact<ArtifactLinkerTag>
+ targetLinkerFileBaseNameNode;
+static const TargetFileBaseNameArtifact<ArtifactPdbTag>
+ targetPdbFileBaseNameNode;
+
+class ArtifactFilePrefixTag;
+class ArtifactLinkerFilePrefixTag;
+class ArtifactFileSuffixTag;
+class ArtifactLinkerFileSuffixTag;
+
+template <typename ArtifactT>
+struct TargetFileArtifactResultGetter
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content);
+};
+
+template <>
+struct TargetFileArtifactResultGetter<ArtifactFilePrefixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent*)
+ {
+ return target->GetFilePrefix(context->Config);
+ }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (!target->IsLinkable()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_LINKER_PREFIX is allowed only for libraries and "
+ "executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+
+ cmStateEnums::ArtifactType artifact =
+ target->HasImportLibrary(context->Config)
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+
+ return target->GetFilePrefix(context->Config, artifact);
+ }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent*)
+ {
+ return target->GetFileSuffix(context->Config);
+ }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag>
+{
+ static std::string Get(cmGeneratorTarget* target,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content)
+ {
+ if (!target->IsLinkable()) {
+ ::reportError(context, content->GetOriginalExpression(),
+ "TARGET_LINKER_SUFFIX is allowed only for libraries and "
+ "executables with ENABLE_EXPORTS.");
+ return std::string();
+ }
+
+ cmStateEnums::ArtifactType artifact =
+ target->HasImportLibrary(context->Config)
+ ? cmStateEnums::ImportLibraryArtifact
+ : cmStateEnums::RuntimeBinaryArtifact;
+
+ return target->GetFileSuffix(context->Config, artifact);
+ }
+};
+
+template <typename ArtifactT>
+struct TargetFileArtifact : public TargetArtifactBase
+{
+ TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
+
+ int NumExpectedParameters() const override { return 1; }
+
+ std::string Evaluate(
+ const std::vector<std::string>& parameters,
+ cmGeneratorExpressionContext* context,
+ const GeneratorExpressionContent* content,
+ cmGeneratorExpressionDAGChecker* dagChecker) const override
+ {
+ cmGeneratorTarget* target =
+ this->GetTarget(parameters, context, content, dagChecker);
+ if (!target) {
+ return std::string();
+ }
+
+ std::string result =
+ TargetFileArtifactResultGetter<ArtifactT>::Get(target, context, content);
+ if (context->HadError) {
+ return std::string();
+ }
+ return result;
+ }
+};
+
+static const TargetFileArtifact<ArtifactFilePrefixTag> targetFilePrefixNode;
+static const TargetFileArtifact<ArtifactLinkerFilePrefixTag>
+ targetLinkerFilePrefixNode;
+static const TargetFileArtifact<ArtifactFileSuffixTag> targetFileSuffixNode;
+static const TargetFileArtifact<ArtifactLinkerFileSuffixTag>
+ targetLinkerFileSuffixNode;
+
static const struct ShellPathNode : public cmGeneratorExpressionNode
{
ShellPathNode() {} // NOLINT(modernize-use-equals-default)
@@ -2047,88 +2250,115 @@ static const struct ShellPathNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* content,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- if (!cmSystemTools::FileIsFullPath(parameters.front())) {
+ std::vector<std::string> listIn;
+ cmSystemTools::ExpandListArgument(parameters.front(), listIn);
+ if (listIn.empty()) {
reportError(context, content->GetOriginalExpression(),
- "\"" + parameters.front() + "\" is not an absolute path.");
+ "\"\" is not an absolute path.");
return std::string();
}
- cmOutputConverter converter(context->LG->GetStateSnapshot());
- return converter.ConvertDirectorySeparatorsForShell(parameters.front());
+ cmStateSnapshot snapshot = context->LG->GetStateSnapshot();
+ cmOutputConverter converter(snapshot);
+ const char* separator = snapshot.GetState()->UseWindowsShell() ? ";" : ":";
+ std::vector<std::string> listOut;
+ listOut.reserve(listIn.size());
+ for (auto const& in : listIn) {
+ if (!cmSystemTools::FileIsFullPath(in)) {
+ reportError(context, content->GetOriginalExpression(),
+ "\"" + in + "\" is not an absolute path.");
+ return std::string();
+ }
+ listOut.emplace_back(converter.ConvertDirectorySeparatorsForShell(in));
+ }
+ return cmJoin(listOut, separator);
}
} shellPathNode;
const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode(
const std::string& identifier)
{
- typedef std::map<std::string, const cmGeneratorExpressionNode*> NodeMap;
- static NodeMap nodeMap;
- if (nodeMap.empty()) {
- nodeMap["0"] = &zeroNode;
- nodeMap["1"] = &oneNode;
- nodeMap["AND"] = &andNode;
- nodeMap["OR"] = &orNode;
- nodeMap["NOT"] = &notNode;
- nodeMap["C_COMPILER_ID"] = &cCompilerIdNode;
- nodeMap["CXX_COMPILER_ID"] = &cxxCompilerIdNode;
- nodeMap["Fortran_COMPILER_ID"] = &fortranCompilerIdNode;
- nodeMap["VERSION_GREATER"] = &versionGreaterNode;
- nodeMap["VERSION_GREATER_EQUAL"] = &versionGreaterEqNode;
- nodeMap["VERSION_LESS"] = &versionLessNode;
- nodeMap["VERSION_LESS_EQUAL"] = &versionLessEqNode;
- nodeMap["VERSION_EQUAL"] = &versionEqualNode;
- nodeMap["C_COMPILER_VERSION"] = &cCompilerVersionNode;
- nodeMap["CXX_COMPILER_VERSION"] = &cxxCompilerVersionNode;
- nodeMap["Fortran_COMPILER_VERSION"] = &fortranCompilerVersionNode;
- nodeMap["PLATFORM_ID"] = &platformIdNode;
- nodeMap["COMPILE_FEATURES"] = &compileFeaturesNode;
- nodeMap["CONFIGURATION"] = &configurationNode;
- nodeMap["CONFIG"] = &configurationTestNode;
- nodeMap["TARGET_FILE"] = &targetNodeGroup.File;
- nodeMap["TARGET_LINKER_FILE"] = &targetLinkerNodeGroup.File;
- nodeMap["TARGET_SONAME_FILE"] = &targetSoNameNodeGroup.File;
- nodeMap["TARGET_PDB_FILE"] = &targetPdbNodeGroup.File;
- nodeMap["TARGET_FILE_NAME"] = &targetNodeGroup.FileName;
- nodeMap["TARGET_LINKER_FILE_NAME"] = &targetLinkerNodeGroup.FileName;
- nodeMap["TARGET_SONAME_FILE_NAME"] = &targetSoNameNodeGroup.FileName;
- nodeMap["TARGET_PDB_FILE_NAME"] = &targetPdbNodeGroup.FileName;
- nodeMap["TARGET_FILE_DIR"] = &targetNodeGroup.FileDir;
- nodeMap["TARGET_LINKER_FILE_DIR"] = &targetLinkerNodeGroup.FileDir;
- nodeMap["TARGET_SONAME_FILE_DIR"] = &targetSoNameNodeGroup.FileDir;
- nodeMap["TARGET_PDB_FILE_DIR"] = &targetPdbNodeGroup.FileDir;
- nodeMap["TARGET_BUNDLE_DIR"] = &targetBundleDirNode;
- nodeMap["TARGET_BUNDLE_CONTENT_DIR"] = &targetBundleContentDirNode;
- nodeMap["STREQUAL"] = &strEqualNode;
- nodeMap["EQUAL"] = &equalNode;
- nodeMap["IN_LIST"] = &inListNode;
- nodeMap["LOWER_CASE"] = &lowerCaseNode;
- nodeMap["UPPER_CASE"] = &upperCaseNode;
- nodeMap["MAKE_C_IDENTIFIER"] = &makeCIdentifierNode;
- nodeMap["BOOL"] = &boolNode;
- nodeMap["IF"] = &ifNode;
- nodeMap["ANGLE-R"] = &angle_rNode;
- nodeMap["COMMA"] = &commaNode;
- nodeMap["SEMICOLON"] = &semicolonNode;
- nodeMap["TARGET_PROPERTY"] = &targetPropertyNode;
- nodeMap["TARGET_NAME"] = &targetNameNode;
- nodeMap["TARGET_OBJECTS"] = &targetObjectsNode;
- nodeMap["TARGET_POLICY"] = &targetPolicyNode;
- nodeMap["TARGET_EXISTS"] = &targetExistsNode;
- nodeMap["TARGET_NAME_IF_EXISTS"] = &targetNameIfExistsNode;
- nodeMap["TARGET_GENEX_EVAL"] = &targetGenexEvalNode;
- nodeMap["GENEX_EVAL"] = &genexEvalNode;
- nodeMap["BUILD_INTERFACE"] = &buildInterfaceNode;
- nodeMap["INSTALL_INTERFACE"] = &installInterfaceNode;
- nodeMap["INSTALL_PREFIX"] = &installPrefixNode;
- nodeMap["JOIN"] = &joinNode;
- nodeMap["LINK_ONLY"] = &linkOnlyNode;
- nodeMap["COMPILE_LANGUAGE"] = &languageNode;
- nodeMap["SHELL_PATH"] = &shellPathNode;
- }
- NodeMap::const_iterator i = nodeMap.find(identifier);
- if (i == nodeMap.end()) {
- return nullptr;
+ static std::map<std::string, cmGeneratorExpressionNode const*> const nodeMap{
+ { "0", &zeroNode },
+ { "1", &oneNode },
+ { "AND", &andNode },
+ { "OR", &orNode },
+ { "NOT", &notNode },
+ { "C_COMPILER_ID", &cCompilerIdNode },
+ { "CXX_COMPILER_ID", &cxxCompilerIdNode },
+ { "CUDA_COMPILER_ID", &cudaCompilerIdNode },
+ { "Fortran_COMPILER_ID", &fortranCompilerIdNode },
+ { "VERSION_GREATER", &versionGreaterNode },
+ { "VERSION_GREATER_EQUAL", &versionGreaterEqNode },
+ { "VERSION_LESS", &versionLessNode },
+ { "VERSION_LESS_EQUAL", &versionLessEqNode },
+ { "VERSION_EQUAL", &versionEqualNode },
+ { "C_COMPILER_VERSION", &cCompilerVersionNode },
+ { "CXX_COMPILER_VERSION", &cxxCompilerVersionNode },
+ { "CUDA_COMPILER_VERSION", &cudaCompilerVersionNode },
+ { "Fortran_COMPILER_VERSION", &fortranCompilerVersionNode },
+ { "PLATFORM_ID", &platformIdNode },
+ { "COMPILE_FEATURES", &compileFeaturesNode },
+ { "CONFIGURATION", &configurationNode },
+ { "CONFIG", &configurationTestNode },
+ { "TARGET_FILE", &targetNodeGroup.File },
+ { "TARGET_LINKER_FILE", &targetLinkerNodeGroup.File },
+ { "TARGET_SONAME_FILE", &targetSoNameNodeGroup.File },
+ { "TARGET_PDB_FILE", &targetPdbNodeGroup.File },
+ { "TARGET_FILE_BASE_NAME", &targetFileBaseNameNode },
+ { "TARGET_LINKER_FILE_BASE_NAME", &targetLinkerFileBaseNameNode },
+ { "TARGET_PDB_FILE_BASE_NAME", &targetPdbFileBaseNameNode },
+ { "TARGET_FILE_PREFIX", &targetFilePrefixNode },
+ { "TARGET_LINKER_FILE_PREFIX", &targetLinkerFilePrefixNode },
+ { "TARGET_FILE_SUFFIX", &targetFileSuffixNode },
+ { "TARGET_LINKER_FILE_SUFFIX", &targetLinkerFileSuffixNode },
+ { "TARGET_FILE_NAME", &targetNodeGroup.FileName },
+ { "TARGET_LINKER_FILE_NAME", &targetLinkerNodeGroup.FileName },
+ { "TARGET_SONAME_FILE_NAME", &targetSoNameNodeGroup.FileName },
+ { "TARGET_PDB_FILE_NAME", &targetPdbNodeGroup.FileName },
+ { "TARGET_FILE_DIR", &targetNodeGroup.FileDir },
+ { "TARGET_LINKER_FILE_DIR", &targetLinkerNodeGroup.FileDir },
+ { "TARGET_SONAME_FILE_DIR", &targetSoNameNodeGroup.FileDir },
+ { "TARGET_PDB_FILE_DIR", &targetPdbNodeGroup.FileDir },
+ { "TARGET_BUNDLE_DIR", &targetBundleDirNode },
+ { "TARGET_BUNDLE_CONTENT_DIR", &targetBundleContentDirNode },
+ { "STREQUAL", &strEqualNode },
+ { "EQUAL", &equalNode },
+ { "IN_LIST", &inListNode },
+ { "FILTER", &filterNode },
+ { "REMOVE_DUPLICATES", &removeDuplicatesNode },
+ { "LOWER_CASE", &lowerCaseNode },
+ { "UPPER_CASE", &upperCaseNode },
+ { "MAKE_C_IDENTIFIER", &makeCIdentifierNode },
+ { "BOOL", &boolNode },
+ { "IF", &ifNode },
+ { "ANGLE-R", &angle_rNode },
+ { "COMMA", &commaNode },
+ { "SEMICOLON", &semicolonNode },
+ { "TARGET_PROPERTY", &targetPropertyNode },
+ { "TARGET_NAME", &targetNameNode },
+ { "TARGET_OBJECTS", &targetObjectsNode },
+ { "TARGET_POLICY", &targetPolicyNode },
+ { "TARGET_EXISTS", &targetExistsNode },
+ { "TARGET_NAME_IF_EXISTS", &targetNameIfExistsNode },
+ { "TARGET_GENEX_EVAL", &targetGenexEvalNode },
+ { "GENEX_EVAL", &genexEvalNode },
+ { "BUILD_INTERFACE", &buildInterfaceNode },
+ { "INSTALL_INTERFACE", &installInterfaceNode },
+ { "INSTALL_PREFIX", &installPrefixNode },
+ { "JOIN", &joinNode },
+ { "LINK_ONLY", &linkOnlyNode },
+ { "COMPILE_LANG_AND_ID", &languageAndIdNode },
+ { "COMPILE_LANGUAGE", &languageNode },
+ { "SHELL_PATH", &shellPathNode }
+ };
+
+ {
+ auto itr = nodeMap.find(identifier);
+ if (itr != nodeMap.end()) {
+ return itr->second;
+ }
}
- return i->second;
+ return nullptr;
}
void reportError(cmGeneratorExpressionContext* context,
diff --git a/Source/cmGeneratorExpressionNode.h b/Source/cmGeneratorExpressionNode.h
index 3dbfc6e5e..7a369249f 100644
--- a/Source/cmGeneratorExpressionNode.h
+++ b/Source/cmGeneratorExpressionNode.h
@@ -20,7 +20,9 @@ struct cmGeneratorExpressionNode
{
DynamicParameters = 0,
OneOrMoreParameters = -1,
- OneOrZeroParameters = -2
+ TwoOrMoreParameters = -2,
+ ZeroOrMoreParameters = -3,
+ OneOrZeroParameters = -4
};
virtual ~cmGeneratorExpressionNode() = default;
diff --git a/Source/cmGeneratorExpressionParser.cxx b/Source/cmGeneratorExpressionParser.cxx
index 949a86d81..304378dfe 100644
--- a/Source/cmGeneratorExpressionParser.cxx
+++ b/Source/cmGeneratorExpressionParser.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGeneratorExpressionParser.h"
+#include "cmAlgorithms.h"
#include "cmGeneratorExpressionEvaluator.h"
#include <assert.h>
@@ -47,14 +48,14 @@ static void extendResult(
if (!result.empty() &&
(*(result.end() - 1))->GetType() ==
cmGeneratorExpressionEvaluator::Text &&
- (*contents.begin())->GetType() == cmGeneratorExpressionEvaluator::Text) {
+ contents.front()->GetType() == cmGeneratorExpressionEvaluator::Text) {
TextContent* textContent = static_cast<TextContent*>(*(result.end() - 1));
textContent->Extend(
- static_cast<TextContent*>(*contents.begin())->GetLength());
- delete *contents.begin();
- result.insert(result.end(), contents.begin() + 1, contents.end());
+ static_cast<TextContent*>(contents.front())->GetLength());
+ delete contents.front();
+ cmAppend(result, contents.begin() + 1, contents.end());
} else {
- result.insert(result.end(), contents.begin(), contents.end());
+ cmAppend(result, contents);
}
}
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 25349d42e..036a07d1c 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -28,6 +28,7 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPropertyMap.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmSourceFileLocation.h"
#include "cmState.h"
@@ -64,20 +65,137 @@ const char* cmTargetPropertyComputer::ComputeLocation<cmGeneratorTarget>(
class cmGeneratorTarget::TargetPropertyEntry
{
+protected:
static cmLinkImplItem NoLinkImplItem;
public:
- TargetPropertyEntry(std::unique_ptr<cmCompiledGeneratorExpression> cge,
- cmLinkImplItem const& item = NoLinkImplItem)
- : ge(std::move(cge))
- , LinkImplItem(item)
+ TargetPropertyEntry(cmLinkImplItem const& item)
+ : LinkImplItem(item)
{
}
- const std::unique_ptr<cmCompiledGeneratorExpression> ge;
+ virtual ~TargetPropertyEntry() = default;
+
+ virtual const std::string& Evaluate(
+ cmLocalGenerator* lg, const std::string& config, bool quiet = false,
+ cmGeneratorTarget const* headTarget = nullptr,
+ cmGeneratorTarget const* currentTarget = nullptr,
+ cmGeneratorExpressionDAGChecker* dagChecker = nullptr,
+ std::string const& language = std::string()) const = 0;
+ virtual const std::string& Evaluate(
+ cmLocalGenerator* lg, const std::string& config, bool quiet,
+ cmGeneratorTarget const* headTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::string const& language = std::string()) const = 0;
+
+ virtual cmListFileBacktrace GetBacktrace() const = 0;
+ virtual std::string const& GetInput() const = 0;
+ virtual bool GetHadContextSensitiveCondition() const { return false; }
+
cmLinkImplItem const& LinkImplItem;
+
+private:
+ cmListFileBacktrace Backtrace;
};
cmLinkImplItem cmGeneratorTarget::TargetPropertyEntry::NoLinkImplItem;
+class TargetPropertyEntryGenex : public cmGeneratorTarget::TargetPropertyEntry
+{
+public:
+ TargetPropertyEntryGenex(std::unique_ptr<cmCompiledGeneratorExpression> cge,
+ cmLinkImplItem const& item = NoLinkImplItem)
+ : cmGeneratorTarget::TargetPropertyEntry(item)
+ , ge(std::move(cge))
+ {
+ }
+
+ const std::string& Evaluate(
+ cmLocalGenerator* lg, const std::string& config, bool quiet = false,
+ cmGeneratorTarget const* headTarget = nullptr,
+ cmGeneratorTarget const* currentTarget = nullptr,
+ cmGeneratorExpressionDAGChecker* dagChecker = nullptr,
+ std::string const& language = std::string()) const override
+ {
+ return this->ge->Evaluate(lg, config, quiet, headTarget, currentTarget,
+ dagChecker, language);
+ }
+ const std::string& Evaluate(
+ cmLocalGenerator* lg, const std::string& config, bool quiet,
+ cmGeneratorTarget const* headTarget,
+ cmGeneratorExpressionDAGChecker* dagChecker,
+ std::string const& language = std::string()) const override
+ {
+ return this->ge->Evaluate(lg, config, quiet, headTarget, dagChecker,
+ language);
+ }
+
+ cmListFileBacktrace GetBacktrace() const override
+ {
+ return this->ge->GetBacktrace();
+ }
+
+ std::string const& GetInput() const override { return this->ge->GetInput(); }
+
+ bool GetHadContextSensitiveCondition() const override
+ {
+ return this->ge->GetHadContextSensitiveCondition();
+ }
+
+private:
+ const std::unique_ptr<cmCompiledGeneratorExpression> ge;
+};
+
+class TargetPropertyEntryString : public cmGeneratorTarget::TargetPropertyEntry
+{
+public:
+ TargetPropertyEntryString(std::string propertyValue,
+ cmListFileBacktrace backtrace,
+ cmLinkImplItem const& item = NoLinkImplItem)
+ : cmGeneratorTarget::TargetPropertyEntry(item)
+ , PropertyValue(std::move(propertyValue))
+ , Backtrace(std::move(backtrace))
+ {
+ }
+
+ const std::string& Evaluate(cmLocalGenerator*, const std::string&, bool,
+ cmGeneratorTarget const*,
+ cmGeneratorTarget const*,
+ cmGeneratorExpressionDAGChecker*,
+ std::string const&) const override
+ {
+ return this->PropertyValue;
+ }
+ const std::string& Evaluate(cmLocalGenerator*, const std::string&, bool,
+ cmGeneratorTarget const*,
+ cmGeneratorExpressionDAGChecker*,
+ std::string const&) const override
+ {
+ return this->PropertyValue;
+ }
+
+ cmListFileBacktrace GetBacktrace() const override { return this->Backtrace; }
+ std::string const& GetInput() const override { return this->PropertyValue; }
+
+private:
+ std::string PropertyValue;
+ cmListFileBacktrace Backtrace;
+};
+
+cmGeneratorTarget::TargetPropertyEntry* CreateTargetPropertyEntry(
+ const std::string& propertyValue,
+ cmListFileBacktrace backtrace = cmListFileBacktrace(),
+ bool evaluateForBuildsystem = false)
+{
+ if (cmGeneratorExpression::Find(propertyValue) != std::string::npos) {
+ cmGeneratorExpression ge(std::move(backtrace));
+ std::unique_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(propertyValue);
+ cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
+ return new TargetPropertyEntryGenex(std::move(cge));
+ }
+
+ return new TargetPropertyEntryString(propertyValue, backtrace);
+}
+
void CreatePropertyGeneratorExpressions(
cmStringRange entries, cmBacktraceRange backtraces,
std::vector<cmGeneratorTarget::TargetPropertyEntry*>& items,
@@ -86,11 +204,8 @@ void CreatePropertyGeneratorExpressions(
std::vector<cmListFileBacktrace>::const_iterator btIt = backtraces.begin();
for (std::vector<std::string>::const_iterator it = entries.begin();
it != entries.end(); ++it, ++btIt) {
- cmGeneratorExpression ge(*btIt);
- std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*it);
- cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
items.push_back(
- new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+ CreateTargetPropertyEntry(*it, *btIt, evaluateForBuildsystem));
}
}
@@ -147,7 +262,7 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
this->DLLPlatform =
!this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
- this->PolicyMap = t->PolicyMap;
+ this->PolicyMap = t->GetPolicyMap();
}
cmGeneratorTarget::~cmGeneratorTarget()
@@ -166,7 +281,7 @@ const char* cmGeneratorTarget::GetSourcesProperty() const
{
std::vector<std::string> values;
for (TargetPropertyEntry* se : this->SourceEntries) {
- values.push_back(se->ge->GetInput());
+ values.push_back(se->GetInput());
}
static std::string value;
value.clear();
@@ -349,6 +464,150 @@ std::string cmGeneratorTarget::GetOutputName(
return i->second;
}
+std::string cmGeneratorTarget::GetFilePrefix(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ if (this->IsImported()) {
+ const char* prefix = this->GetFilePrefixInternal(artifact);
+
+ return prefix ? prefix : std::string();
+ }
+
+ std::string prefix, suffix, base;
+ this->GetFullNameInternal(config, artifact, prefix, base, suffix);
+ return prefix;
+}
+std::string cmGeneratorTarget::GetFileSuffix(
+ const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+ if (this->IsImported()) {
+ const char* suffix = this->GetFileSuffixInternal(artifact);
+
+ return suffix ? suffix : std::string();
+ }
+
+ std::string prefix, suffix, base;
+ this->GetFullNameInternal(config, artifact, prefix, base, suffix);
+ return suffix;
+}
+
+std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const
+{
+ const char* postfix = nullptr;
+ if (!config.empty()) {
+ std::string configProp = cmSystemTools::UpperCase(config);
+ configProp += "_POSTFIX";
+ postfix = this->GetProperty(configProp);
+ // Mac application bundles and frameworks have no postfix.
+ if (!this->IsImported() && postfix &&
+ (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) {
+ postfix = nullptr;
+ }
+ }
+ return postfix ? postfix : std::string();
+}
+
+const char* cmGeneratorTarget::GetFilePrefixInternal(
+ cmStateEnums::ArtifactType artifact, const std::string& language) const
+{
+ // no prefix for non-main target types.
+ if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ return nullptr;
+ }
+
+ const bool isImportedLibraryArtifact =
+ (artifact == cmStateEnums::ImportLibraryArtifact);
+
+ // Return an empty prefix for the import library if this platform
+ // does not support import libraries.
+ if (isImportedLibraryArtifact &&
+ !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
+ return nullptr;
+ }
+
+ // The implib option is only allowed for shared libraries, module
+ // libraries, and executables.
+ if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ artifact = cmStateEnums::RuntimeBinaryArtifact;
+ }
+
+ // Compute prefix value.
+ const char* targetPrefix =
+ (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
+ : this->GetProperty("PREFIX"));
+
+ if (!targetPrefix) {
+ const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
+ if (!language.empty() && prefixVar && *prefixVar) {
+ std::string langPrefix = prefixVar + std::string("_") + language;
+ targetPrefix = this->Makefile->GetDefinition(langPrefix);
+ }
+
+ // if there is no prefix on the target nor specific language
+ // use the cmake definition.
+ if (!targetPrefix && prefixVar) {
+ targetPrefix = this->Makefile->GetDefinition(prefixVar);
+ }
+ }
+
+ return targetPrefix;
+}
+const char* cmGeneratorTarget::GetFileSuffixInternal(
+ cmStateEnums::ArtifactType artifact, const std::string& language) const
+{
+ // no suffix for non-main target types.
+ if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+ this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ return nullptr;
+ }
+
+ const bool isImportedLibraryArtifact =
+ (artifact == cmStateEnums::ImportLibraryArtifact);
+
+ // Return an empty suffix for the import library if this platform
+ // does not support import libraries.
+ if (isImportedLibraryArtifact &&
+ !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
+ return nullptr;
+ }
+
+ // The implib option is only allowed for shared libraries, module
+ // libraries, and executables.
+ if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+ this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+ this->GetType() != cmStateEnums::EXECUTABLE) {
+ artifact = cmStateEnums::RuntimeBinaryArtifact;
+ }
+
+ // Compute suffix value.
+ const char* targetSuffix =
+ (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
+ : this->GetProperty("SUFFIX"));
+
+ if (!targetSuffix) {
+ const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
+ if (!language.empty() && suffixVar && *suffixVar) {
+ std::string langSuffix = suffixVar + std::string("_") + language;
+ targetSuffix = this->Makefile->GetDefinition(langSuffix);
+ }
+
+ // if there is no suffix on the target nor specific language
+ // use the cmake definition.
+ if (!targetSuffix && suffixVar) {
+ targetSuffix = this->Makefile->GetDefinition(suffixVar);
+ }
+ }
+
+ return targetSuffix;
+}
+
void cmGeneratorTarget::ClearSourcesCache()
{
this->KindedSourcesMap.clear();
@@ -358,13 +617,9 @@ void cmGeneratorTarget::ClearSourcesCache()
void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before)
{
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
- std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(src);
- cge->SetEvaluateForBuildsystem(true);
- this->SourceEntries.insert(before ? this->SourceEntries.begin()
- : this->SourceEntries.end(),
- new TargetPropertyEntry(std::move(cge)));
+ this->SourceEntries.insert(
+ before ? this->SourceEntries.begin() : this->SourceEntries.end(),
+ CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true));
this->ClearSourcesCache();
}
@@ -386,14 +641,10 @@ void cmGeneratorTarget::AddIncludeDirectory(const std::string& src,
bool before)
{
this->Target->InsertInclude(src, this->Makefile->GetBacktrace(), before);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
- std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(src);
- cge->SetEvaluateForBuildsystem(true);
this->IncludeDirectoriesEntries.insert(
before ? this->IncludeDirectoriesEntries.begin()
: this->IncludeDirectoriesEntries.end(),
- new TargetPropertyEntry(std::move(cge)));
+ CreateTargetPropertyEntry(src, this->Makefile->GetBacktrace(), true));
}
std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(
@@ -853,8 +1104,7 @@ static void AddInterfaceEntries(
cmGeneratorExpression ge(lib.Backtrace);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
cge->SetEvaluateForBuildsystem(true);
- entries.push_back(
- new cmGeneratorTarget::TargetPropertyEntry(std::move(cge), lib));
+ entries.push_back(new TargetPropertyEntryGenex(std::move(cge), lib));
}
}
}
@@ -876,8 +1126,7 @@ static void AddObjectEntries(
cmGeneratorExpression ge(lib.Backtrace);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
cge->SetEvaluateForBuildsystem(true);
- entries.push_back(
- new cmGeneratorTarget::TargetPropertyEntry(std::move(cge), lib));
+ entries.push_back(new TargetPropertyEntryGenex(std::move(cge), lib));
}
}
}
@@ -899,12 +1148,12 @@ static bool processSources(
cmLinkImplItem const& item = entry->LinkImplItem;
std::string const& targetName = item.AsStr();
std::vector<std::string> entrySources;
- cmSystemTools::ExpandListArgument(
- entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt, tgt,
- dagChecker),
- entrySources);
+ cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(),
+ config, false, tgt, tgt,
+ dagChecker),
+ entrySources);
- if (entry->ge->GetHadContextSensitiveCondition()) {
+ if (entry->GetHadContextSensitiveCondition()) {
contextDependent = true;
}
@@ -939,7 +1188,7 @@ static bool processSources(
std::string usedSources;
for (std::string const& src : entrySources) {
if (uniqueSrcs.insert(src).second) {
- srcs.emplace_back(src, entry->ge->GetBacktrace());
+ srcs.emplace_back(src, entry->GetBacktrace());
if (debugSources) {
usedSources += " * " + src + "\n";
}
@@ -950,7 +1199,7 @@ static bool processSources(
MessageType::LOG,
std::string("Used sources for target ") + tgt->GetName() + ":\n" +
usedSources,
- entry->ge->GetBacktrace());
+ entry->GetBacktrace());
}
}
return contextDependent;
@@ -1606,13 +1855,7 @@ std::string cmGeneratorTarget::GetSOName(const std::string& config) const
return "";
}
// Compute the soname that will be built.
- std::string name;
- std::string soName;
- std::string realName;
- std::string impName;
- std::string pdbName;
- this->GetLibraryNames(name, soName, realName, impName, pdbName, config);
- return soName;
+ return this->GetLibraryNames(config).SharedObject;
}
static bool shouldAddFullLevel(cmGeneratorTarget::BundleDirectoryLevel level)
@@ -2378,7 +2621,7 @@ void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc)
std::set<cmGeneratorTarget*> targets;
for (cmCustomCommandLine const& cCmdLine : cc.GetCommandLines()) {
- std::string const& command = *cCmdLine.begin();
+ std::string const& command = cCmdLine.front();
// Check for a target with this name.
if (cmGeneratorTarget* t =
this->LocalGenerator->FindGeneratorTargetToUse(command)) {
@@ -2534,10 +2777,10 @@ static void processIncludeDirectories(
bool const fromImported = item.Target && item.Target->IsImported();
bool const checkCMP0027 = item.FromGenex;
std::vector<std::string> entryIncludes;
- cmSystemTools::ExpandListArgument(
- entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt,
- dagChecker, language),
- entryIncludes);
+ cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(),
+ config, false, tgt,
+ dagChecker, language),
+ entryIncludes);
std::string usedIncludes;
for (std::string& entryInclude : entryIncludes) {
@@ -2615,7 +2858,7 @@ static void processIncludeDirectories(
std::string inc = entryInclude;
if (uniqueIncludes.insert(inc).second) {
- includes.emplace_back(inc, entry->ge->GetBacktrace());
+ includes.emplace_back(inc, entry->GetBacktrace());
if (debugIncludes) {
usedIncludes += " * " + inc + "\n";
}
@@ -2626,7 +2869,7 @@ static void processIncludeDirectories(
MessageType::LOG,
std::string("Used includes for target ") + tgt->GetName() + ":\n" +
usedIncludes,
- entry->ge->GetBacktrace());
+ entry->GetBacktrace());
}
}
}
@@ -2678,11 +2921,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
libDir = frameworkCheck.match(1);
- cmGeneratorExpression ge;
- std::unique_ptr<cmCompiledGeneratorExpression> cge =
- ge.Parse(libDir.c_str());
linkInterfaceIncludeDirectoriesEntries.push_back(
- new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+ CreateTargetPropertyEntry(libDir));
}
}
@@ -2712,10 +2952,10 @@ static void processOptionsInternal(
{
for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) {
std::vector<std::string> entryOptions;
- cmSystemTools::ExpandListArgument(
- entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt,
- dagChecker, language),
- entryOptions);
+ cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(),
+ config, false, tgt,
+ dagChecker, language),
+ entryOptions);
std::string usedOptions;
for (std::string const& opt : entryOptions) {
if (uniqueOptions.insert(opt).second) {
@@ -2724,10 +2964,10 @@ static void processOptionsInternal(
std::vector<std::string> tmp;
cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp);
for (std::string& o : tmp) {
- options.emplace_back(std::move(o), entry->ge->GetBacktrace());
+ options.emplace_back(std::move(o), entry->GetBacktrace());
}
} else {
- options.emplace_back(opt, entry->ge->GetBacktrace());
+ options.emplace_back(opt, entry->GetBacktrace());
}
if (debugOptions) {
usedOptions += " * " + opt + "\n";
@@ -2739,7 +2979,7 @@ static void processOptionsInternal(
MessageType::LOG,
std::string("Used ") + logName + std::string(" for target ") +
tgt->GetName() + ":\n" + usedOptions,
- entry->ge->GetBacktrace());
+ entry->GetBacktrace());
}
}
}
@@ -2943,11 +3183,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions(
CM_FALLTHROUGH;
}
case cmPolicies::OLD: {
- cmGeneratorExpression ge;
- std::unique_ptr<cmCompiledGeneratorExpression> cge =
- ge.Parse(configProp);
linkInterfaceCompileDefinitionsEntries.push_back(
- new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+ CreateTargetPropertyEntry(configProp));
} break;
case cmPolicies::NEW:
case cmPolicies::REQUIRED_ALWAYS:
@@ -3173,12 +3410,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions(
if (const char* linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
std::vector<std::string> options;
- cmGeneratorExpression ge;
cmSystemTools::ExpandListArgument(linkOptions, options);
for (const auto& option : options) {
- std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(option);
- entries.push_back(
- new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+ entries.push_back(CreateTargetPropertyEntry(option));
}
}
processStaticLibraryLinkOptions(this, entries, result, uniqueOptions,
@@ -3202,10 +3436,10 @@ void processLinkDirectories(
std::string const& targetName = item.AsStr();
std::vector<std::string> entryDirectories;
- cmSystemTools::ExpandListArgument(
- entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt,
- dagChecker, language),
- entryDirectories);
+ cmSystemTools::ExpandListArgument(entry->Evaluate(tgt->GetLocalGenerator(),
+ config, false, tgt,
+ dagChecker, language),
+ entryDirectories);
std::string usedDirectories;
for (std::string& entryDirectory : entryDirectories) {
@@ -3261,7 +3495,7 @@ void processLinkDirectories(
MessageType::LOG,
std::string("Used link directories for target ") + tgt->GetName() +
":\n" + usedDirectories,
- entry->ge->GetBacktrace());
+ entry->GetBacktrace());
}
}
}
@@ -3358,12 +3592,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends(
if (const char* linkDepends = this->GetProperty("LINK_DEPENDS")) {
std::vector<std::string> depends;
- cmGeneratorExpression ge;
cmSystemTools::ExpandListArgument(linkDepends, depends);
for (const auto& depend : depends) {
- std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(depend);
- linkDependsEntries.push_back(
- new cmGeneratorTarget::TargetPropertyEntry(std::move(cge)));
+ linkDependsEntries.push_back(CreateTargetPropertyEntry(depend));
}
}
AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS",
@@ -3383,17 +3614,13 @@ void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
cmGlobalGenerator* gg = this->LocalGenerator->GetGlobalGenerator();
// Get the names.
- std::string name;
- std::string soName;
- std::string realName;
- std::string impName;
- std::string pdbName;
+ cmGeneratorTarget::Names targetNames;
if (this->GetType() == cmStateEnums::EXECUTABLE) {
- this->GetExecutableNames(name, realName, impName, pdbName, config);
+ targetNames = this->GetExecutableNames(config);
} else if (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
this->GetType() == cmStateEnums::SHARED_LIBRARY ||
this->GetType() == cmStateEnums::MODULE_LIBRARY) {
- this->GetLibraryNames(name, soName, realName, impName, pdbName, config);
+ targetNames = this->GetLibraryNames(config);
} else {
return;
}
@@ -3404,34 +3631,34 @@ void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
// Add each name.
std::string f;
- if (!name.empty()) {
+ if (!targetNames.Output.empty()) {
f = dir;
f += "/";
- f += name;
+ f += targetNames.Output;
gg->AddToManifest(f);
}
- if (!soName.empty()) {
+ if (!targetNames.SharedObject.empty()) {
f = dir;
f += "/";
- f += soName;
+ f += targetNames.SharedObject;
gg->AddToManifest(f);
}
- if (!realName.empty()) {
+ if (!targetNames.Real.empty()) {
f = dir;
f += "/";
- f += realName;
+ f += targetNames.Real;
gg->AddToManifest(f);
}
- if (!pdbName.empty()) {
+ if (!targetNames.PDB.empty()) {
f = dir;
f += "/";
- f += pdbName;
+ f += targetNames.PDB;
gg->AddToManifest(f);
}
- if (!impName.empty()) {
+ if (!targetNames.ImportLibrary.empty()) {
f = this->GetDirectory(config, cmStateEnums::ImportLibraryArtifact);
f += "/";
- f += impName;
+ f += targetNames.ImportLibrary;
gg->AddToManifest(f);
}
}
@@ -3509,29 +3736,17 @@ std::string cmGeneratorTarget::NormalGetRealName(
if (this->GetType() == cmStateEnums::EXECUTABLE) {
// Compute the real name that will be built.
- std::string name;
- std::string realName;
- std::string impName;
- std::string pdbName;
- this->GetExecutableNames(name, realName, impName, pdbName, config);
- return realName;
+ return this->GetExecutableNames(config).Real;
}
// Compute the real name that will be built.
- std::string name;
- std::string soName;
- std::string realName;
- std::string impName;
- std::string pdbName;
- this->GetLibraryNames(name, soName, realName, impName, pdbName, config);
- return realName;
-}
-
-void cmGeneratorTarget::GetLibraryNames(std::string& name, std::string& soName,
- std::string& realName,
- std::string& impName,
- std::string& pdbName,
- const std::string& config) const
+ return this->GetLibraryNames(config).Real;
+}
+
+cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
+ const std::string& config) const
{
+ cmGeneratorTarget::Names targetNames;
+
// This should not be called for imported targets.
// TODO: Split cmTarget into a class hierarchy to get compile-time
// enforcement of the limited imported target API.
@@ -3539,7 +3754,6 @@ void cmGeneratorTarget::GetLibraryNames(std::string& name, std::string& soName,
std::string msg = "GetLibraryNames called on imported target: ";
msg += this->GetName();
this->LocalGenerator->IssueMessage(MessageType::INTERNAL_ERROR, msg);
- return;
}
// Check for library version properties.
@@ -3565,50 +3779,51 @@ void cmGeneratorTarget::GetLibraryNames(std::string& name, std::string& soName,
// Get the components of the library name.
std::string prefix;
- std::string base;
std::string suffix;
this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
- prefix, base, suffix);
+ prefix, targetNames.Base, suffix);
// The library name.
- name = prefix + base + suffix;
+ targetNames.Output = prefix + targetNames.Base + suffix;
if (this->IsFrameworkOnApple()) {
- realName = prefix;
+ targetNames.Real = prefix;
if (!this->Makefile->PlatformIsAppleEmbedded()) {
- realName += "Versions/";
- realName += this->GetFrameworkVersion();
- realName += "/";
+ targetNames.Real += "Versions/";
+ targetNames.Real += this->GetFrameworkVersion();
+ targetNames.Real += "/";
}
- realName += base;
- soName = realName;
+ targetNames.Real += targetNames.Base;
+ targetNames.SharedObject = targetNames.Real;
} else {
// The library's soname.
- this->ComputeVersionedName(soName, prefix, base, suffix, name, soversion);
+ this->ComputeVersionedName(targetNames.SharedObject, prefix,
+ targetNames.Base, suffix, targetNames.Output,
+ soversion);
// The library's real name on disk.
- this->ComputeVersionedName(realName, prefix, base, suffix, name, version);
+ this->ComputeVersionedName(targetNames.Real, prefix, targetNames.Base,
+ suffix, targetNames.Output, version);
}
// The import library name.
if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
this->GetType() == cmStateEnums::MODULE_LIBRARY) {
- impName =
+ targetNames.ImportLibrary =
this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
- } else {
- impName.clear();
}
// The program database file name.
- pdbName = this->GetPDBName(config);
+ targetNames.PDB = this->GetPDBName(config);
+
+ return targetNames;
}
-void cmGeneratorTarget::GetExecutableNames(std::string& name,
- std::string& realName,
- std::string& impName,
- std::string& pdbName,
- const std::string& config) const
+cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
+ const std::string& config) const
{
+ cmGeneratorTarget::Names targetNames;
+
// This should not be called for imported targets.
// TODO: Split cmTarget into a class hierarchy to get compile-time
// enforcement of the limited imported target API.
@@ -3633,34 +3848,35 @@ void cmGeneratorTarget::GetExecutableNames(std::string& name,
// Get the components of the executable name.
std::string prefix;
- std::string base;
std::string suffix;
this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
- prefix, base, suffix);
+ prefix, targetNames.Base, suffix);
// The executable name.
- name = prefix + base + suffix;
+ targetNames.Output = prefix + targetNames.Base + suffix;
// The executable's real name on disk.
#if defined(__CYGWIN__)
- realName = prefix + base;
+ targetNames.Real = prefix + targetNames.Base;
#else
- realName = name;
+ targetNames.Real = targetNames.Output;
#endif
if (version) {
- realName += "-";
- realName += version;
+ targetNames.Real += "-";
+ targetNames.Real += version;
}
#if defined(__CYGWIN__)
- realName += suffix;
+ targetNames.Real += suffix;
#endif
// The import library name.
- impName =
+ targetNames.ImportLibrary =
this->GetFullNameInternal(config, cmStateEnums::ImportLibraryArtifact);
// The program database file name.
- pdbName = this->GetPDBName(config);
+ targetNames.PDB = this->GetPDBName(config);
+
+ return targetNames;
}
std::string cmGeneratorTarget::GetFullNameInternal(
@@ -3716,6 +3932,11 @@ void cmGeneratorTarget::GetFullNameInternal(
return;
}
+ // retrieve prefix and suffix
+ std::string ll = this->GetLinkerLanguage(config);
+ const char* targetPrefix = this->GetFilePrefixInternal(artifact, ll);
+ const char* targetSuffix = this->GetFileSuffixInternal(artifact, ll);
+
// The implib option is only allowed for shared libraries, module
// libraries, and executables.
if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
@@ -3725,47 +3946,7 @@ void cmGeneratorTarget::GetFullNameInternal(
}
// Compute the full name for main target types.
- const char* targetPrefix =
- (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
- : this->GetProperty("PREFIX"));
- const char* targetSuffix =
- (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
- : this->GetProperty("SUFFIX"));
- const char* configPostfix = nullptr;
- if (!config.empty()) {
- std::string configProp = cmSystemTools::UpperCase(config);
- configProp += "_POSTFIX";
- configPostfix = this->GetProperty(configProp);
- // Mac application bundles and frameworks have no postfix.
- if (configPostfix &&
- (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) {
- configPostfix = nullptr;
- }
- }
- const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
- const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
-
- // Check for language-specific default prefix and suffix.
- std::string ll = this->GetLinkerLanguage(config);
- if (!ll.empty()) {
- if (!targetSuffix && suffixVar && *suffixVar) {
- std::string langSuff = suffixVar + std::string("_") + ll;
- targetSuffix = this->Makefile->GetDefinition(langSuff);
- }
- if (!targetPrefix && prefixVar && *prefixVar) {
- std::string langPrefix = prefixVar + std::string("_") + ll;
- targetPrefix = this->Makefile->GetDefinition(langPrefix);
- }
- }
-
- // if there is no prefix on the target use the cmake definition
- if (!targetPrefix && prefixVar) {
- targetPrefix = this->Makefile->GetSafeDefinition(prefixVar).c_str();
- }
- // if there is no suffix on the target use the cmake definition
- if (!targetSuffix && suffixVar) {
- targetSuffix = this->Makefile->GetSafeDefinition(suffixVar).c_str();
- }
+ const std::string configPostfix = this->GetFilePostfix(config);
// frameworks have directory prefix but no suffix
std::string fw_prefix;
@@ -3790,7 +3971,7 @@ void cmGeneratorTarget::GetFullNameInternal(
outBase += this->GetOutputName(config, artifact);
// Append the per-configuration postfix.
- outBase += configPostfix ? configPostfix : "";
+ outBase += configPostfix;
// Name shared libraries with their version number on some platforms.
if (const char* soversion = this->GetProperty("SOVERSION")) {
@@ -3812,6 +3993,31 @@ std::string cmGeneratorTarget::GetLinkerLanguage(
return this->GetLinkClosure(config)->LinkerLanguage;
}
+std::string cmGeneratorTarget::GetPDBOutputName(
+ const std::string& config) const
+{
+ std::string base =
+ this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact);
+
+ std::vector<std::string> props;
+ std::string configUpper = cmSystemTools::UpperCase(config);
+ if (!configUpper.empty()) {
+ // PDB_NAME_<CONFIG>
+ props.push_back("PDB_NAME_" + configUpper);
+ }
+
+ // PDB_NAME
+ props.emplace_back("PDB_NAME");
+
+ for (std::string const& p : props) {
+ if (const char* outName = this->GetProperty(p)) {
+ base = outName;
+ break;
+ }
+ }
+ return base;
+}
+
std::string cmGeneratorTarget::GetPDBName(const std::string& config) const
{
std::string prefix;
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 59d38afd7..0e0ee6a6f 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -69,9 +69,9 @@ public:
std::string GetExportName() const;
std::vector<std::string> GetPropertyKeys() const;
- ///! Might return a nullptr if the property is not set or invalid
+ //! Might return a nullptr if the property is not set or invalid
const char* GetProperty(const std::string& prop) const;
- ///! Always returns a valid pointer
+ //! Always returns a valid pointer
const char* GetSafeProperty(const std::string& prop) const;
bool GetPropertyAsBool(const std::string& prop) const;
void GetSourceFiles(std::vector<cmSourceFile*>& files,
@@ -503,6 +503,9 @@ public:
OutputInfo const* GetOutputInfo(const std::string& config) const;
+ // Get the target PDB base name.
+ std::string GetPDBOutputName(const std::string& config) const;
+
/** Get the name of the pdb file for the target. */
std::string GetPDBName(const std::string& config = "") const;
@@ -531,6 +534,18 @@ public:
std::string GetOutputName(const std::string& config,
cmStateEnums::ArtifactType artifact) const;
+ /** Get target file prefix */
+ std::string GetFilePrefix(const std::string& config,
+ cmStateEnums::ArtifactType artifact =
+ cmStateEnums::RuntimeBinaryArtifact) const;
+ /** Get target file prefix */
+ std::string GetFileSuffix(const std::string& config,
+ cmStateEnums::ArtifactType artifact =
+ cmStateEnums::RuntimeBinaryArtifact) const;
+
+ /** Get target file postfix */
+ std::string GetFilePostfix(const std::string& config) const;
+
/** Clears cached meta data for local and external source files.
* The meta data will be recomputed on demand.
*/
@@ -568,19 +583,25 @@ public:
void GetAutoUicOptions(std::vector<std::string>& result,
const std::string& config) const;
+ struct Names
+ {
+ std::string Base;
+ std::string Output;
+ std::string Real;
+ std::string ImportLibrary;
+ std::string PDB;
+ std::string SharedObject;
+ };
+
/** Get the names of the executable needed to generate a build rule
that takes into account executable version numbers. This should
be called only on an executable target. */
- void GetExecutableNames(std::string& name, std::string& realName,
- std::string& impName, std::string& pdbName,
- const std::string& config) const;
+ Names GetExecutableNames(const std::string& config) const;
/** Get the names of the library needed to generate a build rule
that takes into account shared library version numbers. This
should be called only on a library target. */
- void GetLibraryNames(std::string& name, std::string& soName,
- std::string& realName, std::string& impName,
- std::string& pdbName, const std::string& config) const;
+ Names GetLibraryNames(const std::string& config) const;
/**
* Compute whether this target must be relinked before installing.
@@ -596,7 +617,7 @@ public:
pdb output directory is given. */
std::string GetPDBDirectory(const std::string& config) const;
- ///! Return the preferred linker language for this target
+ //! Return the preferred linker language for this target
std::string GetLinkerLanguage(const std::string& config) const;
/** Does this target have a GNU implib to convert to MS format? */
@@ -719,6 +740,11 @@ private:
mutable std::map<std::string, bool> DebugCompatiblePropertiesDone;
+ const char* GetFilePrefixInternal(cmStateEnums::ArtifactType artifact,
+ const std::string& language = "") const;
+ const char* GetFileSuffixInternal(cmStateEnums::ArtifactType artifact,
+ const std::string& language = "") const;
+
std::string GetFullNameInternal(const std::string& config,
cmStateEnums::ArtifactType artifact) const;
void GetFullNameInternal(const std::string& config,
diff --git a/Source/cmGetPipes.cxx b/Source/cmGetPipes.cxx
new file mode 100644
index 000000000..ad323f7ee
--- /dev/null
+++ b/Source/cmGetPipes.cxx
@@ -0,0 +1,48 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGetPipes.h"
+
+#include "cm_uv.h"
+
+#include <fcntl.h>
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <io.h>
+
+int cmGetPipes(int* fds)
+{
+ SECURITY_ATTRIBUTES attr;
+ HANDLE readh, writeh;
+ attr.nLength = sizeof(attr);
+ attr.lpSecurityDescriptor = nullptr;
+ attr.bInheritHandle = FALSE;
+ if (!CreatePipe(&readh, &writeh, &attr, 0))
+ return uv_translate_sys_error(GetLastError());
+ fds[0] = _open_osfhandle((intptr_t)readh, 0);
+ fds[1] = _open_osfhandle((intptr_t)writeh, 0);
+ if (fds[0] == -1 || fds[1] == -1) {
+ CloseHandle(readh);
+ CloseHandle(writeh);
+ return uv_translate_sys_error(GetLastError());
+ }
+ return 0;
+}
+#else
+# include <errno.h>
+# include <unistd.h>
+
+int cmGetPipes(int* fds)
+{
+ if (pipe(fds) == -1) {
+ return uv_translate_sys_error(errno);
+ }
+
+ if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
+ fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
+ close(fds[0]);
+ close(fds[1]);
+ return uv_translate_sys_error(errno);
+ }
+ return 0;
+}
+#endif
diff --git a/Source/cmGetPipes.h b/Source/cmGetPipes.h
new file mode 100644
index 000000000..2a46b51b3
--- /dev/null
+++ b/Source/cmGetPipes.h
@@ -0,0 +1,8 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmGetPipes_h
+#define cmGetPipes_h
+
+int cmGetPipes(int* fds);
+
+#endif
diff --git a/Source/cmGhsMultiGpj.cxx b/Source/cmGhsMultiGpj.cxx
index c1f0742f2..da27971de 100644
--- a/Source/cmGhsMultiGpj.cxx
+++ b/Source/cmGhsMultiGpj.cxx
@@ -2,16 +2,17 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGhsMultiGpj.h"
-#include "cmGeneratedFileStream.h"
+#include <ostream>
static const char* GHS_TAG[] = { "[INTEGRITY Application]",
"[Library]",
"[Project]",
"[Program]",
"[Reference]",
- "[Subproject]" };
+ "[Subproject]",
+ "[Custom Target]" };
-const char* GhsMultiGpj::GetGpjTag(Types const gpjType)
+const char* GhsMultiGpj::GetGpjTag(Types gpjType)
{
char const* tag;
switch (gpjType) {
@@ -21,6 +22,7 @@ const char* GhsMultiGpj::GetGpjTag(Types const gpjType)
case PROGRAM:
case REFERENCE:
case SUBPROJECT:
+ case CUSTOM_TARGET:
tag = GHS_TAG[gpjType];
break;
default:
@@ -29,7 +31,7 @@ const char* GhsMultiGpj::GetGpjTag(Types const gpjType)
return tag;
}
-void GhsMultiGpj::WriteGpjTag(Types const gpjType, std::ostream& fout)
+void GhsMultiGpj::WriteGpjTag(Types gpjType, std::ostream& fout)
{
char const* tag;
tag = GhsMultiGpj::GetGpjTag(gpjType);
diff --git a/Source/cmGhsMultiGpj.h b/Source/cmGhsMultiGpj.h
index 6d59225da..e588150f4 100644
--- a/Source/cmGhsMultiGpj.h
+++ b/Source/cmGhsMultiGpj.h
@@ -6,8 +6,6 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <iosfwd>
-class cmGeneratedFileStream;
-
class GhsMultiGpj
{
public:
@@ -18,12 +16,13 @@ public:
PROJECT,
PROGRAM,
REFERENCE,
- SUBPROJECT
+ SUBPROJECT,
+ CUSTOM_TARGET
};
- static void WriteGpjTag(Types const gpjType, std::ostream& fout);
+ static void WriteGpjTag(Types gpjType, std::ostream& fout);
- static const char* GetGpjTag(Types const gpjType);
+ static const char* GetGpjTag(Types gpjType);
};
#endif // ! cmGhsMultiGpjType_h
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index 5fe350c10..b80da7231 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -2,23 +2,41 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGhsMultiTargetGenerator.h"
-#include "cmComputeLinkInformation.h"
+#include "cmCustomCommand.h"
+#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGhsMultiGenerator.h"
#include "cmLinkLineComputer.h"
+#include "cmLocalGenerator.h"
#include "cmLocalGhsMultiGenerator.h"
#include "cmMakefile.h"
+#include "cmOutputConverter.h"
#include "cmSourceFile.h"
+#include "cmSourceFileLocation.h"
#include "cmSourceGroup.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
#include "cmTarget.h"
+#include <algorithm>
+#include <ostream>
+#include <set>
+#include <utility>
+
cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target)
: GeneratorTarget(target)
, LocalGenerator(
static_cast<cmLocalGhsMultiGenerator*>(target->GetLocalGenerator()))
, Makefile(target->Target->GetMakefile())
, Name(target->GetName())
+#ifdef _WIN32
+ , CmdWindowsShell(true)
+#else
+ , CmdWindowsShell(false)
+#endif
{
// Store the configuration name that is being used
if (const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) {
@@ -30,9 +48,7 @@ cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target)
}
}
-cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator()
-{
-}
+cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator() = default;
void cmGhsMultiTargetGenerator::Generate()
{
@@ -40,12 +56,8 @@ void cmGhsMultiTargetGenerator::Generate()
switch (this->GeneratorTarget->GetType()) {
case cmStateEnums::EXECUTABLE: {
// Get the name of the executable to generate.
- std::string targetName;
- std::string targetNameImport;
- std::string targetNamePDB;
- this->GeneratorTarget->GetExecutableNames(
- targetName, this->TargetNameReal, targetNameImport, targetNamePDB,
- this->ConfigName);
+ this->TargetNameReal =
+ this->GeneratorTarget->GetExecutableNames(this->ConfigName).Real;
if (cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) {
this->TagType = GhsMultiGpj::INTERGRITY_APPLICATION;
} else {
@@ -54,13 +66,8 @@ void cmGhsMultiTargetGenerator::Generate()
break;
}
case cmStateEnums::STATIC_LIBRARY: {
- std::string targetName;
- std::string targetNameSO;
- std::string targetNameImport;
- std::string targetNamePDB;
- this->GeneratorTarget->GetLibraryNames(
- targetName, targetNameSO, this->TargetNameReal, targetNameImport,
- targetNamePDB, this->ConfigName);
+ this->TargetNameReal =
+ this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real;
this->TagType = GhsMultiGpj::LIBRARY;
break;
}
@@ -71,13 +78,8 @@ void cmGhsMultiTargetGenerator::Generate()
return;
}
case cmStateEnums::OBJECT_LIBRARY: {
- std::string targetName;
- std::string targetNameSO;
- std::string targetNameImport;
- std::string targetNamePDB;
- this->GeneratorTarget->GetLibraryNames(
- targetName, targetNameSO, this->TargetNameReal, targetNameImport,
- targetNamePDB, this->ConfigName);
+ this->TargetNameReal =
+ this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real;
this->TagType = GhsMultiGpj::SUBPROJECT;
break;
}
@@ -88,10 +90,19 @@ void cmGhsMultiTargetGenerator::Generate()
return;
}
case cmStateEnums::UTILITY: {
- std::string msg = "add_custom_target(<name> ...) not supported: ";
- msg += this->Name;
- cmSystemTools::Message(msg);
- return;
+ this->TargetNameReal = this->GeneratorTarget->GetName();
+ this->TagType = GhsMultiGpj::CUSTOM_TARGET;
+ break;
+ }
+ case cmStateEnums::GLOBAL_TARGET: {
+ this->TargetNameReal = this->GeneratorTarget->GetName();
+ if (this->TargetNameReal ==
+ this->GetGlobalGenerator()->GetInstallTargetName()) {
+ this->TagType = GhsMultiGpj::CUSTOM_TARGET;
+ } else {
+ return;
+ }
+ break;
}
default:
return;
@@ -108,29 +119,29 @@ void cmGhsMultiTargetGenerator::Generate()
void cmGhsMultiTargetGenerator::GenerateTarget()
{
- // Open the filestream in copy-if-different mode.
- std::string fname = this->LocalGenerator->GetCurrentBinaryDirectory();
- fname += "/";
- fname += this->Name;
- fname += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
- cmGeneratedFileStream fout(fname.c_str());
+ // Open the target file in copy-if-different mode.
+ std::string fproj = this->LocalGenerator->GetCurrentBinaryDirectory();
+ fproj += "/";
+ fproj += this->Name;
+ fproj += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
+ cmGeneratedFileStream fout(fproj);
fout.SetCopyIfDifferent(true);
this->GetGlobalGenerator()->WriteFileHeader(fout);
GhsMultiGpj::WriteGpjTag(this->TagType, fout);
- const std::string language(
- this->GeneratorTarget->GetLinkerLanguage(this->ConfigName));
-
- this->WriteTargetSpecifics(fout, this->ConfigName);
- this->SetCompilerFlags(this->ConfigName, language);
- this->WriteCompilerFlags(fout, this->ConfigName, language);
- this->WriteCompilerDefinitions(fout, this->ConfigName, language);
- this->WriteIncludes(fout, this->ConfigName, language);
- this->WriteTargetLinkLine(fout, this->ConfigName);
- this->WriteCustomCommands(fout);
+ if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+ const std::string language(
+ this->GeneratorTarget->GetLinkerLanguage(this->ConfigName));
+ this->WriteTargetSpecifics(fout, this->ConfigName);
+ this->SetCompilerFlags(this->ConfigName, language);
+ this->WriteCompilerFlags(fout, this->ConfigName, language);
+ this->WriteCompilerDefinitions(fout, this->ConfigName, language);
+ this->WriteIncludes(fout, this->ConfigName, language);
+ this->WriteTargetLinkLine(fout, this->ConfigName);
+ this->WriteBuildEvents(fout);
+ }
this->WriteSources(fout);
- this->WriteReferences(fout);
fout.Close();
}
@@ -224,7 +235,7 @@ void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::ostream& fout,
if (flagsByLangI != this->FlagsByLanguage.end()) {
if (!flagsByLangI->second.empty()) {
std::vector<std::string> ghsCompFlags =
- cmSystemTools::ParseArguments(flagsByLangI->second.c_str());
+ cmSystemTools::ParseArguments(flagsByLangI->second);
for (auto& f : ghsCompFlags) {
fout << " " << f << std::endl;
}
@@ -238,10 +249,8 @@ void cmGhsMultiTargetGenerator::WriteCompilerDefinitions(
std::vector<std::string> compileDefinitions;
this->GeneratorTarget->GetCompileDefinitions(compileDefinitions, config,
language);
- for (std::vector<std::string>::const_iterator cdI =
- compileDefinitions.begin();
- cdI != compileDefinitions.end(); ++cdI) {
- fout << " -D" << (*cdI) << std::endl;
+ for (std::string const& compileDefinition : compileDefinitions) {
+ fout << " -D" << compileDefinition << std::endl;
}
}
@@ -253,9 +262,8 @@ void cmGhsMultiTargetGenerator::WriteIncludes(std::ostream& fout,
this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
language, config);
- for (std::vector<std::string>::const_iterator includes_i = includes.begin();
- includes_i != includes.end(); ++includes_i) {
- fout << " -I\"" << *includes_i << "\"" << std::endl;
+ for (std::string const& include : includes) {
+ fout << " -I\"" << include << "\"" << std::endl;
}
}
@@ -282,16 +290,14 @@ void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout,
frameworkPath, linkPath, this->GeneratorTarget);
// write out link options
- std::vector<std::string> lopts =
- cmSystemTools::ParseArguments(linkFlags.c_str());
+ std::vector<std::string> lopts = cmSystemTools::ParseArguments(linkFlags);
for (auto& l : lopts) {
fout << " " << l << std::endl;
}
// write out link search paths
// must be quoted for paths that contain spaces
- std::vector<std::string> lpath =
- cmSystemTools::ParseArguments(linkPath.c_str());
+ std::vector<std::string> lpath = cmSystemTools::ParseArguments(linkPath);
for (auto& l : lpath) {
fout << " -L\"" << l << "\"" << std::endl;
}
@@ -301,68 +307,161 @@ void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout,
std::string cbd = this->LocalGenerator->GetCurrentBinaryDirectory();
std::vector<std::string> llibs =
- cmSystemTools::ParseArguments(linkLibraries.c_str());
+ cmSystemTools::ParseArguments(linkLibraries);
for (auto& l : llibs) {
if (l.compare(0, 2, "-l") == 0) {
fout << " \"" << l << "\"" << std::endl;
} else {
- std::string rl = cmSystemTools::CollapseCombinedPath(cbd, l);
+ std::string rl = cmSystemTools::CollapseFullPath(l, cbd);
fout << " -l\"" << rl << "\"" << std::endl;
}
}
}
-void cmGhsMultiTargetGenerator::WriteCustomCommands(std::ostream& fout)
+void cmGhsMultiTargetGenerator::WriteBuildEvents(std::ostream& fout)
{
- WriteCustomCommandsHelper(fout, this->GeneratorTarget->GetPreBuildCommands(),
- cmTarget::PRE_BUILD);
- WriteCustomCommandsHelper(
- fout, this->GeneratorTarget->GetPostBuildCommands(), cmTarget::POST_BUILD);
+ this->WriteBuildEventsHelper(
+ fout, this->GeneratorTarget->GetPreBuildCommands(),
+ std::string("prebuild"), std::string("preexecShell"));
+
+ if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+ this->WriteBuildEventsHelper(
+ fout, this->GeneratorTarget->GetPreLinkCommands(),
+ std::string("prelink"), std::string("preexecShell"));
+ }
+
+ this->WriteBuildEventsHelper(
+ fout, this->GeneratorTarget->GetPostBuildCommands(),
+ std::string("postbuild"), std::string("postexecShell"));
+}
+
+void cmGhsMultiTargetGenerator::WriteBuildEventsHelper(
+ std::ostream& fout, const std::vector<cmCustomCommand>& ccv,
+ std::string const& name, std::string const& cmd)
+{
+ int cmdcount = 0;
+
+ for (cmCustomCommand const& cc : ccv) {
+ cmCustomCommandGenerator ccg(cc, this->ConfigName, this->LocalGenerator);
+ // Open the filestream for this custom command
+ std::string fname = this->LocalGenerator->GetCurrentBinaryDirectory();
+ fname +=
+ "/" + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ fname += "/" + this->Name + "_" + name;
+ fname += std::to_string(cmdcount++);
+ fname += this->CmdWindowsShell ? ".bat" : ".sh";
+ cmGeneratedFileStream f(fname);
+ f.SetCopyIfDifferent(true);
+ this->WriteCustomCommandsHelper(f, ccg);
+ f.Close();
+ if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
+ fout << " :" << cmd << "=\"" << fname << "\"" << std::endl;
+ } else {
+ fout << fname << std::endl;
+ fout << " :outputName=\"" << fname << ".rule\"" << std::endl;
+ }
+ for (auto& byp : ccg.GetByproducts()) {
+ fout << " :extraOutputFile=\"" << byp << "\"" << std::endl;
+ }
+ }
}
void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
- std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet,
- cmTarget::CustomCommandType const commandType)
+ std::ostream& fout, cmCustomCommandGenerator const& ccg)
{
- for (std::vector<cmCustomCommand>::const_iterator commandsSetI =
- commandsSet.begin();
- commandsSetI != commandsSet.end(); ++commandsSetI) {
- cmCustomCommandLines const& commands = commandsSetI->GetCommandLines();
- for (cmCustomCommandLines::const_iterator commandI = commands.begin();
- commandI != commands.end(); ++commandI) {
- switch (commandType) {
- case cmTarget::PRE_BUILD:
- fout << " :preexecShellSafe=";
- break;
- case cmTarget::POST_BUILD:
- fout << " :postexecShellSafe=";
- break;
- default:
- assert("Only pre and post are supported");
- }
- cmCustomCommandLine const& command = *commandI;
- for (cmCustomCommandLine::const_iterator commandLineI = command.begin();
- commandLineI != command.end(); ++commandLineI) {
- std::string subCommandE =
- this->LocalGenerator->EscapeForShell(*commandLineI, true);
- if (!command.empty()) {
- fout << (command.begin() == commandLineI ? "'" : " ");
- // Need to double escape backslashes
- cmSystemTools::ReplaceString(subCommandE, "\\", "\\\\");
+ std::vector<std::string> cmdLines;
+
+ // if the command specified a working directory use it.
+ std::string dir = this->LocalGenerator->GetCurrentBinaryDirectory();
+ std::string currentBinDir = dir;
+ std::string workingDir = ccg.GetWorkingDirectory();
+ if (!workingDir.empty()) {
+ dir = workingDir;
+ }
+
+ // Line to check for error between commands.
+#ifdef _WIN32
+ std::string check_error = "if %errorlevel% neq 0 exit /b %errorlevel%";
+#else
+ std::string check_error = "if [[ $? -ne 0 ]]; then exit 1; fi";
+#endif
+
+#ifdef _WIN32
+ cmdLines.push_back("@echo off");
+#endif
+ // Echo the custom command's comment text.
+ const char* comment = ccg.GetComment();
+ if (comment && *comment) {
+ std::string echocmd = "echo ";
+ echocmd += comment;
+ cmdLines.push_back(std::move(echocmd));
+ }
+
+ // Switch to working directory
+ std::string cdCmd;
+#ifdef _WIN32
+ std::string cdStr = "cd /D ";
+#else
+ std::string cdStr = "cd ";
+#endif
+ cdCmd = cdStr +
+ this->LocalGenerator->ConvertToOutputFormat(dir, cmOutputConverter::SHELL);
+ cmdLines.push_back(std::move(cdCmd));
+
+ for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
+ // Build the command line in a single string.
+ std::string cmd = ccg.GetCommand(c);
+ if (!cmd.empty()) {
+ // Use "call " before any invocations of .bat or .cmd files
+ // invoked as custom commands in the WindowsShell.
+ //
+ bool useCall = false;
+
+ if (this->CmdWindowsShell) {
+ std::string suffix;
+ if (cmd.size() > 4) {
+ suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size() - 4));
+ if (suffix == ".bat" || suffix == ".cmd") {
+ useCall = true;
+ }
}
- fout << subCommandE;
}
- if (!command.empty()) {
- fout << "'" << std::endl;
+
+ cmSystemTools::ReplaceString(cmd, "/./", "/");
+ // Convert the command to a relative path only if the current
+ // working directory will be the start-output directory.
+ bool had_slash = cmd.find('/') != std::string::npos;
+ if (workingDir.empty()) {
+ cmd =
+ this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir, cmd);
+ }
+ bool has_slash = cmd.find('/') != std::string::npos;
+ if (had_slash && !has_slash) {
+ // This command was specified as a path to a file in the
+ // current directory. Add a leading "./" so it can run
+ // without the current directory being in the search path.
+ cmd = "./" + cmd;
}
+ cmd = this->LocalGenerator->ConvertToOutputFormat(
+ cmd, cmOutputConverter::SHELL);
+ if (useCall) {
+ cmd = "call " + cmd;
+ }
+ ccg.AppendArguments(c, cmd);
+ cmdLines.push_back(std::move(cmd));
}
}
+
+ // push back the custom commands
+ for (auto const& c : cmdLines) {
+ fout << c << std::endl;
+ fout << check_error << std::endl;
+ }
}
-void cmGhsMultiTargetGenerator::WriteSourceProperty(std::ostream& fout,
- const cmSourceFile* sf,
- std::string propName,
- std::string propFlag)
+void cmGhsMultiTargetGenerator::WriteSourceProperty(
+ std::ostream& fout, const cmSourceFile* sf, std::string const& propName,
+ std::string const& propFlag)
{
const char* prop = sf->GetProperty(propName);
if (prop) {
@@ -393,12 +492,12 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
this->Makefile->FindSourceGroup(sf->GetFullPath(), sourceGroups);
std::string gn = sourceGroup->GetFullName();
groupFiles[gn].push_back(sf);
- groupNames.insert(gn);
+ groupNames.insert(std::move(gn));
}
/* list of known groups and the order they are displayed in a project file */
const std::vector<std::string> standardGroups = {
- "Header Files", "Source Files", "CMake Rules",
+ "CMake Rules", "Header Files", "Source Files",
"Object Files", "Object Libraries", "Resources"
};
@@ -416,11 +515,19 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
groupFilesList[i] = *n;
i += 1;
groupNames.erase(gn);
+ } else if (this->TagType == GhsMultiGpj::CUSTOM_TARGET &&
+ gn == "CMake Rules") {
+ /* make sure that rules folder always exists in case of custom targets
+ * that have no custom commands except for pre or post build events.
+ */
+ groupFilesList.resize(groupFilesList.size() + 1);
+ groupFilesList[i] = gn;
+ i += 1;
}
}
{ /* catch-all group - is last item */
- std::string gn = "";
+ std::string gn;
auto n = groupNames.find(gn);
if (n != groupNames.end()) {
groupFilesList.back() = *n;
@@ -446,7 +553,7 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
/* write files into the proper project file
* -- groups go into main project file
- * unless FOLDER property or variable is set.
+ * unless NO_SOURCE_GROUP_FILE property or variable is set.
*/
for (auto& sg : groupFilesList) {
std::ostream* fout;
@@ -469,7 +576,7 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
std::string fpath = this->LocalGenerator->GetCurrentBinaryDirectory();
fpath += "/";
fpath += lpath;
- cmGeneratedFileStream* f = new cmGeneratedFileStream(fpath.c_str());
+ cmGeneratedFileStream* f = new cmGeneratedFileStream(fpath);
f->SetCopyIfDifferent(true);
gfiles.push_back(f);
fout = f;
@@ -485,33 +592,98 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
} else {
*fout << "{comment} " << sg << std::endl;
}
+ } else if (sg.empty()) {
+ *fout << "{comment} Others" << std::endl;
}
- /* output rule for each source file */
- for (const cmSourceFile* si : groupFiles[sg]) {
-
- // Convert filename to native system
- // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on
- // windows when opening some files from the search window.
- std::string fname(si->GetFullPath());
- cmSystemTools::ConvertToOutputSlashes(fname);
- *fout << fname << std::endl;
+ if (sg != "CMake Rules") {
+ /* output rule for each source file */
+ for (const cmSourceFile* si : groupFiles[sg]) {
+ bool compile = true;
+ // Convert filename to native system
+ // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on
+ // windows when opening some files from the search window.
+ std::string fname(si->GetFullPath());
+ cmSystemTools::ConvertToOutputSlashes(fname);
+
+ /* For custom targets list any associated sources,
+ * comment out source code to prevent it from being
+ * compiled when processing this target.
+ * Otherwise, comment out any custom command (main) dependencies that
+ * are listed as source files to prevent them from being considered
+ * part of the build.
+ */
+ std::string comment;
+ if ((this->TagType == GhsMultiGpj::CUSTOM_TARGET &&
+ !si->GetLanguage().empty()) ||
+ si->GetCustomCommand()) {
+ comment = "{comment} ";
+ compile = false;
+ }
- if ("ld" != si->GetExtension() && "int" != si->GetExtension() &&
- "bsp" != si->GetExtension()) {
- this->WriteObjectLangOverride(*fout, si);
+ *fout << comment << fname << std::endl;
+ if (compile) {
+ if ("ld" != si->GetExtension() && "int" != si->GetExtension() &&
+ "bsp" != si->GetExtension()) {
+ WriteObjectLangOverride(*fout, si);
+ }
+
+ this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I");
+ this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D");
+ this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", "");
+
+ /* to avoid clutter in the GUI only print out the objectName if it
+ * has been renamed */
+ std::string objectName = this->GeneratorTarget->GetObjectName(si);
+ if (!objectName.empty() &&
+ this->GeneratorTarget->HasExplicitObjectName(si)) {
+ *fout << " -o " << objectName << std::endl;
+ }
+ }
}
-
- this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I");
- this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D");
- this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", "");
-
- /* to avoid clutter in the gui only print out the objectName if it has
- * been renamed */
- std::string objectName = this->GeneratorTarget->GetObjectName(si);
- if (!objectName.empty() &&
- this->GeneratorTarget->HasExplicitObjectName(si)) {
- *fout << " -o " << objectName << std::endl;
+ } else {
+ std::vector<cmSourceFile const*> customCommands;
+ if (ComputeCustomCommandOrder(customCommands)) {
+ std::string message = "The custom commands for target [" +
+ this->GeneratorTarget->GetName() + "] had a cycle.\n";
+ cmSystemTools::Error(message);
+ } else {
+ /* Custom targets do not have a dependency on SOURCES files.
+ * Therefore the dependency list may include SOURCES files after the
+ * custom target. Because nothing can depend on the custom target just
+ * move it to the last item.
+ */
+ for (auto sf = customCommands.begin(); sf != customCommands.end();
+ ++sf) {
+ if (((*sf)->GetLocation()).GetName() == this->Name + ".rule") {
+ std::rotate(sf, sf + 1, customCommands.end());
+ break;
+ }
+ }
+ int cmdcount = 0;
+ for (auto& sf : customCommands) {
+ const cmCustomCommand* cc = sf->GetCustomCommand();
+ cmCustomCommandGenerator ccg(*cc, this->ConfigName,
+ this->LocalGenerator);
+
+ // Open the filestream for this custom command
+ std::string fname =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+ fname += "/" +
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ fname += "/" + this->Name + "_cc";
+ fname += std::to_string(cmdcount++) + "_";
+ fname += (sf->GetLocation()).GetName();
+ fname += this->CmdWindowsShell ? ".bat" : ".sh";
+ cmGeneratedFileStream f(fname);
+ f.SetCopyIfDifferent(true);
+ this->WriteCustomCommandsHelper(f, ccg);
+ f.Close();
+ this->WriteCustomCommandLine(*fout, fname, ccg);
+ }
+ }
+ if (this->TagType == GhsMultiGpj::CUSTOM_TARGET) {
+ this->WriteBuildEvents(*fout);
}
}
}
@@ -521,62 +693,107 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
}
}
+void cmGhsMultiTargetGenerator::WriteCustomCommandLine(
+ std::ostream& fout, std::string& fname, cmCustomCommandGenerator const& ccg)
+{
+ /* NOTE: Customization Files are not well documented. Testing showed
+ * that ":outputName=file" can only be used once per script. The
+ * script will only run if ":outputName=file" is missing or just run
+ * once if ":outputName=file" is not specified. If there are
+ * multiple outputs then the script needs to be listed multiple times
+ * for each output. Otherwise it won't rerun the script if one of
+ * the outputs is manually deleted.
+ */
+ bool specifyExtra = true;
+ for (auto& out : ccg.GetOutputs()) {
+ fout << fname << std::endl;
+ fout << " :outputName=\"" << out << "\"" << std::endl;
+ if (specifyExtra) {
+ for (auto& byp : ccg.GetByproducts()) {
+ fout << " :extraOutputFile=\"" << byp << "\"" << std::endl;
+ }
+ for (auto& dep : ccg.GetDepends()) {
+ fout << " :depends=\"" << dep << "\"" << std::endl;
+ }
+ specifyExtra = false;
+ }
+ }
+}
+
void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
std::ostream& fout, const cmSourceFile* sourceFile)
{
const char* rawLangProp = sourceFile->GetProperty("LANGUAGE");
- if (NULL != rawLangProp) {
+ if (nullptr != rawLangProp) {
std::string sourceLangProp(rawLangProp);
- std::string extension(sourceFile->GetExtension());
+ std::string const& extension = sourceFile->GetExtension();
if ("CXX" == sourceLangProp && ("c" == extension || "C" == extension)) {
fout << " -dotciscxx" << std::endl;
}
}
}
-void cmGhsMultiTargetGenerator::WriteReferences(std::ostream& fout)
+bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()
{
- // This only applies to INTEGRITY Applications
- if (this->TagType != GhsMultiGpj::INTERGRITY_APPLICATION) {
- return;
+ const char* p = this->GeneratorTarget->GetProperty("ghs_integrity_app");
+ if (p) {
+ return cmSystemTools::IsOn(
+ this->GeneratorTarget->GetProperty("ghs_integrity_app"));
}
+ std::vector<cmSourceFile*> sources;
+ this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
+ for (auto& sf : sources) {
+ if ("int" == sf->GetExtension()) {
+ return true;
+ }
+ }
+ return false;
+}
- // Get the targets that this one depends upon
- cmTargetDependSet unordered =
- this->GetGlobalGenerator()->GetTargetDirectDepends(this->GeneratorTarget);
- cmGlobalGhsMultiGenerator::OrderedTargetDependSet ordered(unordered,
- this->Name);
- for (auto& t : ordered) {
- std::string tname = t->GetName();
- std::string tpath = t->LocalGenerator->GetCurrentBinaryDirectory();
- std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory();
- std::string outpath =
- this->LocalGenerator->MaybeConvertToRelativePath(rootpath, tpath) + "/" +
- tname + "REF" + cmGlobalGhsMultiGenerator::FILE_EXTENSION;
+bool cmGhsMultiTargetGenerator::ComputeCustomCommandOrder(
+ std::vector<cmSourceFile const*>& order)
+{
+ std::set<cmSourceFile const*> temp;
+ std::set<cmSourceFile const*> perm;
- fout << outpath;
- fout << " ";
- GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fout);
+ // Collect all custom commands for this target
+ std::vector<cmSourceFile const*> customCommands;
+ this->GeneratorTarget->GetCustomCommands(customCommands, this->ConfigName);
- // Tell the global generator that a refernce project needs to be created
- t->Target->SetProperty("GHS_REFERENCE_PROJECT", "ON");
+ for (cmSourceFile const* si : customCommands) {
+ bool r = VisitCustomCommand(temp, perm, order, si);
+ if (r) {
+ return r;
+ }
}
+ return false;
}
-bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp(void)
+bool cmGhsMultiTargetGenerator::VisitCustomCommand(
+ std::set<cmSourceFile const*>& temp, std::set<cmSourceFile const*>& perm,
+ std::vector<cmSourceFile const*>& order, cmSourceFile const* si)
{
- const char* p = this->GeneratorTarget->GetProperty("ghs_integrity_app");
- if (p) {
- return cmSystemTools::IsOn(
- this->GeneratorTarget->GetProperty("ghs_integrity_app"));
- } else {
- std::vector<cmSourceFile*> sources;
- this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
- for (auto& sf : sources) {
- if ("int" == sf->GetExtension()) {
- return true;
+ /* check if permanent mark is set*/
+ if (perm.find(si) == perm.end()) {
+ /* set temporary mark; check if revisit*/
+ if (temp.insert(si).second) {
+ for (auto& di : si->GetCustomCommand()->GetDepends()) {
+ cmSourceFile const* sf = this->GeneratorTarget->GetLocalGenerator()
+ ->GetMakefile()
+ ->GetSourceFileWithOutput(di);
+ /* if sf exists then visit */
+ if (sf && this->VisitCustomCommand(temp, perm, order, sf)) {
+ return true;
+ }
}
+ /* mark as complete; insert into beginning of list*/
+ perm.insert(si);
+ order.push_back(si);
+ return false;
}
- return false;
+ /* revisiting item - not a DAG */
+ return true;
}
+ /* already complete */
+ return false;
}
diff --git a/Source/cmGhsMultiTargetGenerator.h b/Source/cmGhsMultiTargetGenerator.h
index a241cc6bd..a131567c8 100644
--- a/Source/cmGhsMultiTargetGenerator.h
+++ b/Source/cmGhsMultiTargetGenerator.h
@@ -5,10 +5,14 @@
#include "cmGhsMultiGpj.h"
-#include "cmTarget.h"
+#include <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
class cmCustomCommand;
-class cmGeneratedFileStream;
+class cmCustomCommandGenerator;
class cmGeneratorTarget;
class cmGlobalGhsMultiGenerator;
class cmLocalGhsMultiGenerator;
@@ -45,18 +49,27 @@ private:
void WriteIncludes(std::ostream& fout, const std::string& config,
const std::string& language);
void WriteTargetLinkLine(std::ostream& fout, std::string const& config);
- void WriteCustomCommands(std::ostream& fout);
- void WriteCustomCommandsHelper(
- std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet,
- cmTarget::CustomCommandType commandType);
+ void WriteBuildEvents(std::ostream& fout);
+ void WriteBuildEventsHelper(std::ostream& fout,
+ const std::vector<cmCustomCommand>& ccv,
+ std::string const& name, std::string const& cmd);
+ void WriteCustomCommandsHelper(std::ostream& fout,
+ cmCustomCommandGenerator const& ccg);
+ void WriteCustomCommandLine(std::ostream& fout, std::string& fname,
+ cmCustomCommandGenerator const& ccg);
+ bool ComputeCustomCommandOrder(std::vector<cmSourceFile const*>& order);
+ bool VisitCustomCommand(std::set<cmSourceFile const*>& temp,
+ std::set<cmSourceFile const*>& perm,
+ std::vector<cmSourceFile const*>& order,
+ cmSourceFile const* sf);
void WriteSources(std::ostream& fout_proj);
void WriteSourceProperty(std::ostream& fout, const cmSourceFile* sf,
- std::string propName, std::string propFlag);
- void WriteReferences(std::ostream& fout);
+ std::string const& propName,
+ std::string const& propFlag);
static void WriteObjectLangOverride(std::ostream& fout,
const cmSourceFile* sourceFile);
- bool DetermineIfIntegrityApp(void);
+ bool DetermineIfIntegrityApp();
cmGeneratorTarget* GeneratorTarget;
cmLocalGhsMultiGenerator* LocalGenerator;
cmMakefile* Makefile;
@@ -66,7 +79,8 @@ private:
std::string TargetNameReal;
GhsMultiGpj::Types TagType;
std::string const Name;
- std::string ConfigName; /* CMAKE_BUILD_TYPE */
+ std::string ConfigName; /* CMAKE_BUILD_TYPE */
+ bool const CmdWindowsShell; /* custom commands run in cmd.exe or /bin/sh */
};
#endif // ! cmGhsMultiTargetGenerator_h
diff --git a/Source/cmGlobVerificationManager.cxx b/Source/cmGlobVerificationManager.cxx
index 5fd890eab..9fb417098 100644
--- a/Source/cmGlobVerificationManager.cxx
+++ b/Source/cmGlobVerificationManager.cxx
@@ -25,8 +25,8 @@ bool cmGlobVerificationManager::SaveVerificationScript(const std::string& path)
cmGeneratedFileStream verifyScriptFile(scriptFile);
verifyScriptFile.SetCopyIfDifferent(true);
if (!verifyScriptFile) {
- cmSystemTools::Error("Unable to open verification script file for save. ",
- scriptFile.c_str());
+ cmSystemTools::Error("Unable to open verification script file for save. " +
+ scriptFile);
cmSystemTools::ReportLastSystemError("");
return false;
}
@@ -71,8 +71,8 @@ bool cmGlobVerificationManager::SaveVerificationScript(const std::string& path)
cmsys::ofstream verifyStampFile(stampFile.c_str());
if (!verifyStampFile) {
- cmSystemTools::Error("Unable to open verification stamp file for write. ",
- stampFile.c_str());
+ cmSystemTools::Error("Unable to open verification stamp file for write. " +
+ stampFile);
return false;
}
verifyStampFile << "# This file is generated by CMake for checking of the "
diff --git a/Source/cmGlobVerificationManager.h b/Source/cmGlobVerificationManager.h
index f7146bec0..48606d3f3 100644
--- a/Source/cmGlobVerificationManager.h
+++ b/Source/cmGlobVerificationManager.h
@@ -22,11 +22,11 @@
class cmGlobVerificationManager
{
protected:
- ///! Save verification script for given makefile.
- ///! Saves to output <path>/<CMakeFilesDirectory>/VerifyGlobs.cmake
+ //! Save verification script for given makefile.
+ //! Saves to output <path>/<CMakeFilesDirectory>/VerifyGlobs.cmake
bool SaveVerificationScript(const std::string& path);
- ///! Add an entry into the glob cache
+ //! Add an entry into the glob cache
void AddCacheEntry(bool recurse, bool listDirectories, bool followSymlinks,
const std::string& relative,
const std::string& expression,
@@ -34,13 +34,13 @@ protected:
const std::string& variable,
const cmListFileBacktrace& bt);
- ///! Clear the glob cache for state reset.
+ //! Clear the glob cache for state reset.
void Reset();
- ///! Check targets should be written in generated build system.
+ //! Check targets should be written in generated build system.
bool DoWriteVerifyTarget() const;
- ///! Get the paths to the generated script and stamp files
+ //! Get the paths to the generated script and stamp files
std::string const& GetVerifyScript() const { return this->VerifyScript; }
std::string const& GetVerifyStamp() const { return this->VerifyStamp; }
diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx
index c2eb583a9..51d681dee 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.cxx
+++ b/Source/cmGlobalBorlandMakefileGenerator.cxx
@@ -34,7 +34,7 @@ void cmGlobalBorlandMakefileGenerator::EnableLanguage(
this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
}
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
cmLocalGenerator* cmGlobalBorlandMakefileGenerator::CreateLocalGenerator(
cmMakefile* mf)
{
@@ -53,15 +53,16 @@ void cmGlobalBorlandMakefileGenerator::GetDocumentation(
entry.Brief = "Generates Borland makefiles.";
}
-void cmGlobalBorlandMakefileGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& projectDir,
- const std::string& targetName, const std::string& config, bool fast,
- int /*jobs*/, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalBorlandMakefileGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int /*jobs*/, bool verbose,
+ std::vector<std::string> const& makeOptions)
{
- this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
- makeCommand, makeProgram, projectName, projectDir, targetName, config,
- fast, cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
+ return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast,
+ cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
}
void cmGlobalBorlandMakefileGenerator::PrintBuildCommandAdvice(
diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h
index ca04b7b73..ee7de70f6 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.h
+++ b/Source/cmGlobalBorlandMakefileGenerator.h
@@ -22,7 +22,7 @@ public:
cmGlobalBorlandMakefileGenerator>();
}
- ///! Get the name for the generator.
+ //! Get the name for the generator.
std::string GetName() const override
{
return cmGlobalBorlandMakefileGenerator::GetActualName();
@@ -32,7 +32,7 @@ public:
/** Get the documentation entry for this generator. */
static void GetDocumentation(cmDocumentationEntry& entry);
- ///! Create a local generator appropriate to this Global Generator
+ //! Create a local generator appropriate to this Global Generator
cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
/**
@@ -46,15 +46,12 @@ public:
bool AllowDeleteOnError() const override { return false; }
protected:
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
};
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 8a3720fe6..4eba4ff93 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -7,6 +7,7 @@
#include <algorithm>
#include <assert.h>
#include <cstring>
+#include <initializer_list>
#include <iterator>
#include <sstream>
#include <stdio.h>
@@ -34,6 +35,7 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmState.h"
#include "cmStateDirectory.h"
@@ -211,7 +213,7 @@ void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang,
if (!mf->GetDefinition(langComp)) {
if (!optional) {
- cmSystemTools::Error(langComp.c_str(), " not set, after EnableLanguage");
+ cmSystemTools::Error(langComp + " not set, after EnableLanguage");
}
return;
}
@@ -270,8 +272,7 @@ void cmGlobalGenerator::AddBuildExportExportSet(
bool cmGlobalGenerator::GenerateImportFile(const std::string& file)
{
- std::map<std::string, cmExportBuildFileGenerator*>::iterator it =
- this->BuildExportSets.find(file);
+ auto const it = this->BuildExportSets.find(file);
if (it != this->BuildExportSets.end()) {
bool result = it->second->GenerateImportFile();
@@ -297,10 +298,7 @@ bool cmGlobalGenerator::CheckTargetsForMissingSources() const
{
bool failed = false;
for (cmLocalGenerator* localGen : this->LocalGenerators) {
- const std::vector<cmGeneratorTarget*>& targets =
- localGen->GetGeneratorTargets();
-
- for (cmGeneratorTarget* target : targets) {
+ for (cmGeneratorTarget* target : localGen->GetGeneratorTargets()) {
if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET ||
target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY ||
target->GetType() == cmStateEnums::TargetType::UTILITY ||
@@ -314,9 +312,11 @@ bool cmGlobalGenerator::CheckTargetsForMissingSources() const
if (configs.empty()) {
target->GetSourceFiles(srcs, "");
} else {
- for (std::vector<std::string>::const_iterator ci = configs.begin();
- ci != configs.end() && srcs.empty(); ++ci) {
- target->GetSourceFiles(srcs, *ci);
+ for (std::string const& config : configs) {
+ target->GetSourceFiles(srcs, config);
+ if (srcs.empty()) {
+ break;
+ }
}
}
if (srcs.empty()) {
@@ -331,11 +331,41 @@ bool cmGlobalGenerator::CheckTargetsForMissingSources() const
return failed;
}
+bool cmGlobalGenerator::CheckTargetsForType() const
+{
+ if (!this->GetLanguageEnabled("Swift")) {
+ return false;
+ }
+ bool failed = false;
+ for (cmLocalGenerator* generator : this->LocalGenerators) {
+ for (cmGeneratorTarget* target : generator->GetGeneratorTargets()) {
+ std::vector<std::string> configs;
+ target->Makefile->GetConfigurations(configs);
+ if (configs.empty()) {
+ configs.emplace_back();
+ }
+
+ for (std::string const& config : configs) {
+ if (target->GetLinkerLanguage(config) == "Swift") {
+ if (target->GetPropertyAsBool("WIN32_EXECUTABLE")) {
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "WIN32_EXECUTABLE property is not supported on Swift "
+ "executables",
+ target->GetBacktrace());
+ failed = true;
+ }
+ }
+ }
+ }
+ }
+ return failed;
+}
+
bool cmGlobalGenerator::IsExportedTargetsFile(
const std::string& filename) const
{
- const std::map<std::string, cmExportBuildFileGenerator*>::const_iterator it =
- this->BuildExportSets.find(filename);
+ auto const it = this->BuildExportSets.find(filename);
if (it == this->BuildExportSets.end()) {
return false;
}
@@ -536,11 +566,22 @@ void cmGlobalGenerator::EnableLanguage(
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# pragma warning(push)
-# pragma warning(disable : 4996)
+# 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
-# pragma warning(pop)
+# ifdef __clang__
+# pragma clang diagnostic pop
+# else
+# pragma warning(pop)
+# endif
# endif
std::ostringstream windowsVersionString;
windowsVersionString << osviex.dwMajorVersion << "."
@@ -635,8 +676,7 @@ void cmGlobalGenerator::EnableLanguage(
// to avoid duplicate compiler tests.
if (cmSystemTools::FileExists(fpath)) {
if (!mf->ReadListFile(fpath)) {
- cmSystemTools::Error("Could not find cmake module file: ",
- fpath.c_str());
+ cmSystemTools::Error("Could not find cmake module file: " + fpath);
}
// if this file was found then the language was already determined
// to be working
@@ -661,8 +701,8 @@ void cmGlobalGenerator::EnableLanguage(
determineCompiler += "Compiler.cmake";
std::string determineFile = mf->GetModulesFile(determineCompiler);
if (!mf->ReadListFile(determineFile)) {
- cmSystemTools::Error("Could not find cmake module file: ",
- determineCompiler.c_str());
+ cmSystemTools::Error("Could not find cmake module file: " +
+ determineCompiler);
}
if (cmSystemTools::GetFatalErrorOccured()) {
return;
@@ -680,8 +720,9 @@ void cmGlobalGenerator::EnableLanguage(
std::string compilerEnv = "CMAKE_";
compilerEnv += lang;
compilerEnv += "_COMPILER_ENV_VAR";
- std::string envVar = mf->GetRequiredDefinition(compilerEnv);
- std::string envVarValue = mf->GetRequiredDefinition(compilerName);
+ const std::string& envVar = mf->GetRequiredDefinition(compilerEnv);
+ const std::string& envVarValue =
+ mf->GetRequiredDefinition(compilerName);
std::string env = envVar;
env += "=";
env += envVarValue;
@@ -695,8 +736,7 @@ void cmGlobalGenerator::EnableLanguage(
fpath += lang;
fpath += "Compiler.cmake";
if (!mf->ReadListFile(fpath)) {
- cmSystemTools::Error("Could not find cmake module file: ",
- fpath.c_str());
+ cmSystemTools::Error("Could not find cmake module file: " + fpath);
}
this->SetLanguageEnabledFlag(lang, mf);
needSetLanguageEnabledMaps[lang] = true;
@@ -788,11 +828,10 @@ void cmGlobalGenerator::EnableLanguage(
fpath += "Information.cmake";
std::string informationFile = mf->GetModulesFile(fpath);
if (informationFile.empty()) {
- cmSystemTools::Error("Could not find cmake module file: ",
- fpath.c_str());
+ cmSystemTools::Error("Could not find cmake module file: " + fpath);
} else if (!mf->ReadListFile(informationFile)) {
- cmSystemTools::Error("Could not process cmake module file: ",
- informationFile.c_str());
+ cmSystemTools::Error("Could not process cmake module file: " +
+ informationFile);
}
}
if (needSetLanguageEnabledMaps[lang]) {
@@ -812,8 +851,8 @@ void cmGlobalGenerator::EnableLanguage(
testLang += "Compiler.cmake";
std::string ifpath = mf->GetModulesFile(testLang);
if (!mf->ReadListFile(ifpath)) {
- cmSystemTools::Error("Could not find cmake module file: ",
- testLang.c_str());
+ cmSystemTools::Error("Could not find cmake module file: " +
+ testLang);
}
std::string compilerWorks = "CMAKE_";
compilerWorks += lang;
@@ -898,7 +937,7 @@ void cmGlobalGenerator::CheckCompilerIdCompatibility(
/* clang-format off */
w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0025) << "\n"
"Converting " << lang <<
- " compiler id \"AppleClang\" to \"Clang\" for compatibility."
+ R"( compiler id "AppleClang" to "Clang" for compatibility.)"
;
/* clang-format on */
mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
@@ -928,7 +967,7 @@ void cmGlobalGenerator::CheckCompilerIdCompatibility(
/* clang-format off */
w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0047) << "\n"
"Converting " << lang <<
- " compiler id \"QCC\" to \"GNU\" for compatibility."
+ R"( compiler id "QCC" to "GNU" for compatibility.)"
;
/* clang-format on */
mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
@@ -954,6 +993,36 @@ void cmGlobalGenerator::CheckCompilerIdCompatibility(
break;
}
}
+
+ if (strcmp(compilerId, "XLClang") == 0) {
+ switch (mf->GetPolicyStatus(cmPolicies::CMP0089)) {
+ case cmPolicies::WARN:
+ if (!this->CMakeInstance->GetIsInTryCompile() &&
+ mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0089")) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0089) << "\n"
+ "Converting " << lang <<
+ R"( compiler id "XLClang" to "XL" for compatibility.)"
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // OLD behavior is to convert XLClang to XL.
+ mf->AddDefinition(compilerIdVar, "XL");
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ mf->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0089));
+ case cmPolicies::NEW:
+ // NEW behavior is to keep AppleClang.
+ break;
+ }
+ }
}
std::string cmGlobalGenerator::GetLanguageOutputExtension(
@@ -961,9 +1030,7 @@ std::string cmGlobalGenerator::GetLanguageOutputExtension(
{
const std::string& lang = source.GetLanguage();
if (!lang.empty()) {
- std::map<std::string, std::string>::const_iterator it =
- this->LanguageToOutputExtension.find(lang);
-
+ auto const it = this->LanguageToOutputExtension.find(lang);
if (it != this->LanguageToOutputExtension.end()) {
return it->second;
}
@@ -988,8 +1055,7 @@ std::string cmGlobalGenerator::GetLanguageFromExtension(const char* ext) const
if (ext && *ext == '.') {
++ext;
}
- std::map<std::string, std::string>::const_iterator it =
- this->ExtensionToLanguage.find(ext);
+ auto const it = this->ExtensionToLanguage.find(ext);
if (it != this->ExtensionToLanguage.end()) {
return it->second;
}
@@ -1182,14 +1248,16 @@ void cmGlobalGenerator::Configure()
this->ConfigureDoneCMP0026AndCMP0024 = true;
// Put a copy of each global target in every directory.
- std::vector<GlobalTargetInfo> globalTargets;
- this->CreateDefaultGlobalTargets(globalTargets);
-
- for (cmMakefile* mf : this->Makefiles) {
- cmTargets* targets = &(mf->GetTargets());
- for (GlobalTargetInfo const& globalTarget : globalTargets) {
- targets->insert(cmTargets::value_type(
- globalTarget.Name, this->CreateGlobalTarget(globalTarget, mf)));
+ {
+ std::vector<GlobalTargetInfo> globalTargets;
+ this->CreateDefaultGlobalTargets(globalTargets);
+
+ for (cmMakefile* mf : this->Makefiles) {
+ auto& targets = mf->GetTargets();
+ for (GlobalTargetInfo const& globalTarget : globalTargets) {
+ targets.emplace(globalTarget.Name,
+ this->CreateGlobalTarget(globalTarget, mf));
+ }
}
}
@@ -1222,7 +1290,7 @@ void cmGlobalGenerator::Configure()
} else {
msg << "Configuring done";
}
- this->CMakeInstance->UpdateProgress(msg.str().c_str(), -1);
+ this->CMakeInstance->UpdateProgress(msg.str(), -1);
}
}
@@ -1238,7 +1306,7 @@ void cmGlobalGenerator::CreateImportedGenerationObjects(
std::vector<const cmGeneratorTarget*>& exports)
{
this->CreateGenerationObjects(ImportedOnly);
- std::vector<cmMakefile*>::iterator mfit =
+ auto const mfit =
std::find(this->Makefiles.begin(), this->Makefiles.end(), mf);
cmLocalGenerator* lg =
this->LocalGenerators[std::distance(this->Makefiles.begin(), mfit)];
@@ -1253,8 +1321,7 @@ void cmGlobalGenerator::CreateImportedGenerationObjects(
cmExportBuildFileGenerator* cmGlobalGenerator::GetExportedTargetsFile(
const std::string& filename) const
{
- std::map<std::string, cmExportBuildFileGenerator*>::const_iterator it =
- this->BuildExportSets.find(filename);
+ auto const it = this->BuildExportSets.find(filename);
return it == this->BuildExportSets.end() ? nullptr : it->second;
}
@@ -1347,7 +1414,9 @@ bool cmGlobalGenerator::Compute()
for (cmLocalGenerator* localGen : this->LocalGenerators) {
cmMakefile* mf = localGen->GetMakefile();
for (cmInstallGenerator* g : mf->GetInstallGenerators()) {
- g->Compute(localGen);
+ if (!g->Compute(localGen)) {
+ return false;
+ }
}
}
@@ -1376,6 +1445,10 @@ bool cmGlobalGenerator::Compute()
return false;
}
+ if (this->CheckTargetsForType()) {
+ return false;
+ }
+
for (cmLocalGenerator* localGen : this->LocalGenerators) {
localGen->ComputeHomeRelativeOutputPath();
}
@@ -1468,8 +1541,7 @@ bool cmGlobalGenerator::ComputeTargetDepends()
if (!ctd.Compute()) {
return false;
}
- std::vector<cmGeneratorTarget const*> const& targets = ctd.GetTargets();
- for (cmGeneratorTarget const* target : targets) {
+ for (cmGeneratorTarget const* target : ctd.GetTargets()) {
ctd.GetTargetDirectDepends(target, this->TargetDependencies[target]);
}
return true;
@@ -1509,8 +1581,7 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo()
const cmBacktraceRange noconfig_compile_definitions_bts =
mf->GetCompileDefinitionsBacktraces();
- cmTargets& targets = mf->GetTargets();
- for (auto& target : targets) {
+ for (auto& target : mf->GetTargets()) {
cmTarget* t = &target.second;
if (t->GetType() == cmStateEnums::GLOBAL_TARGET) {
continue;
@@ -1522,12 +1593,12 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo()
continue;
}
- cmBacktraceRange::const_iterator btIt =
- noconfig_compile_definitions_bts.begin();
- for (cmStringRange::const_iterator it =
- noconfig_compile_definitions.begin();
- it != noconfig_compile_definitions.end(); ++it, ++btIt) {
- t->InsertCompileDefinition(*it, *btIt);
+ {
+ auto btIt = noconfig_compile_definitions_bts.begin();
+ auto it = noconfig_compile_definitions.begin();
+ for (; it != noconfig_compile_definitions.end(); ++it, ++btIt) {
+ t->InsertCompileDefinition(*it, *btIt);
+ }
}
cmPolicies::PolicyStatus polSt =
@@ -1567,17 +1638,14 @@ void cmGlobalGenerator::CreateGeneratorTargets(
std::map<cmTarget*, cmGeneratorTarget*> const& importedMap)
{
if (targetTypes == AllTargets) {
- cmTargets& targets = mf->GetTargets();
- for (auto& target : targets) {
+ for (auto& target : mf->GetTargets()) {
cmTarget* t = &target.second;
cmGeneratorTarget* gt = new cmGeneratorTarget(t, lg);
lg->AddGeneratorTarget(gt);
}
}
- std::vector<cmTarget*> itgts = mf->GetImportedTargets();
-
- for (cmTarget* t : itgts) {
+ for (cmTarget* t : mf->GetImportedTargets()) {
lg->AddImportedGeneratorTarget(importedMap.find(t)->second);
}
}
@@ -1613,6 +1681,7 @@ void cmGlobalGenerator::ClearGeneratorMembers()
cmDeleteAll(this->LocalGenerators);
this->LocalGenerators.clear();
+ this->AliasTargets.clear();
this->ExportSets.clear();
this->TargetDependencies.clear();
this->TargetSearchIndex.clear();
@@ -1638,14 +1707,11 @@ void cmGlobalGenerator::CheckTargetProperties()
cmState* state = this->GetCMakeInstance()->GetState();
for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
this->Makefiles[i]->ConfigureFinalPass();
- cmTargets& targets = this->Makefiles[i]->GetTargets();
- for (auto const& target : targets) {
+ for (auto const& target : this->Makefiles[i]->GetTargets()) {
if (target.second.GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
- const cmTarget::LinkLibraryVectorType& libs =
- target.second.GetOriginalLinkLibraries();
- for (auto const& lib : libs) {
+ for (auto const& lib : target.second.GetOriginalLinkLibraries()) {
if (lib.first.size() > 9 &&
cmSystemTools::IsNOTFOUND(lib.first.c_str())) {
std::string varName = lib.first.substr(0, lib.first.size() - 9);
@@ -1702,8 +1768,8 @@ void cmGlobalGenerator::CheckTargetProperties()
cmSystemTools::Error("The following variables are used in this project, "
"but they are set to NOTFOUND.\n"
"Please set them or make sure they are set and "
- "tested correctly in the CMake files:\n",
- notFoundVars.c_str());
+ "tested correctly in the CMake files:\n" +
+ notFoundVars);
}
}
@@ -1731,20 +1797,9 @@ int cmGlobalGenerator::TryCompile(int jobs, const std::string& srcdir,
this->FirstTimeProgress);
}
- std::string newTarget;
+ std::vector<std::string> newTarget = {};
if (!target.empty()) {
- newTarget += target;
-#if 0
-# if defined(_WIN32) || defined(__CYGWIN__)
- std::string tmp = target;
- // if the target does not already end in . something
- // then assume .exe
- if(tmp.size() < 4 || tmp[tmp.size()-4] != '.')
- {
- newTarget += ".exe";
- }
-# endif // WIN32
-#endif
+ newTarget = { target };
}
std::string config =
mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
@@ -1752,14 +1807,16 @@ int cmGlobalGenerator::TryCompile(int jobs, const std::string& srcdir,
config, false, fast, false, this->TryCompileTimeout);
}
-void cmGlobalGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& /*unused*/,
- const std::string& /*unused*/, const std::string& /*unused*/,
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalGenerator::GenerateBuildCommand(
const std::string& /*unused*/, const std::string& /*unused*/,
- bool /*unused*/, int /*unused*/, bool /*unused*/,
- std::vector<std::string> const& /*unused*/)
+ const std::string& /*unused*/, std::vector<std::string> const& /*unused*/,
+ const std::string& /*unused*/, bool /*unused*/, int /*unused*/,
+ bool /*unused*/, std::vector<std::string> const& /*unused*/)
{
- makeCommand.add("cmGlobalGenerator::GenerateBuildCommand not implemented");
+ GeneratedMakeCommand makeCommand;
+ makeCommand.Add("cmGlobalGenerator::GenerateBuildCommand not implemented");
+ return { std::move(makeCommand) };
}
void cmGlobalGenerator::PrintBuildCommandAdvice(std::ostream& /*os*/,
@@ -1769,15 +1826,13 @@ void cmGlobalGenerator::PrintBuildCommandAdvice(std::ostream& /*os*/,
// they do not support certain build command line options
}
-int cmGlobalGenerator::Build(int jobs, const std::string& /*unused*/,
- const std::string& bindir,
- const std::string& projectName,
- const std::string& target, std::string& output,
- const std::string& makeCommandCSTR,
- const std::string& config, bool clean, bool fast,
- bool verbose, cmDuration timeout,
- cmSystemTools::OutputOption outputflag,
- std::vector<std::string> const& nativeOptions)
+int cmGlobalGenerator::Build(
+ int jobs, const std::string& /*unused*/, const std::string& bindir,
+ const std::string& projectName, const std::vector<std::string>& targets,
+ std::string& output, const std::string& makeCommandCSTR,
+ const std::string& config, bool clean, bool fast, bool verbose,
+ cmDuration timeout, cmSystemTools::OutputOption outputflag,
+ std::vector<std::string> const& nativeOptions)
{
bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
@@ -1790,40 +1845,45 @@ int cmGlobalGenerator::Build(int jobs, const std::string& /*unused*/,
output += "\n";
if (workdir.Failed()) {
cmSystemTools::SetRunCommandHideConsole(hideconsole);
- cmSystemTools::Error("Failed to change directory: ",
- std::strerror(workdir.GetLastResult()));
- output += "Failed to change directory: ";
- output += std::strerror(workdir.GetLastResult());
+ std::string err = "Failed to change directory: ";
+ err += std::strerror(workdir.GetLastResult());
+ cmSystemTools::Error(err);
+ output += err;
output += "\n";
return 1;
}
- int retVal;
+ int retVal = 0;
cmSystemTools::SetRunCommandHideConsole(true);
std::string outputBuffer;
std::string* outputPtr = &outputBuffer;
- GeneratedMakeCommand makeCommand;
- this->GenerateBuildCommand(makeCommand, makeCommandCSTR, projectName, bindir,
- target, config, fast, jobs, verbose,
- nativeOptions);
+ std::vector<GeneratedMakeCommand> makeCommand =
+ this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, targets,
+ config, fast, jobs, verbose, nativeOptions);
// Workaround to convince some commands to produce output.
if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH &&
- makeCommand.RequiresOutputForward) {
+ makeCommand.back().RequiresOutputForward) {
outputflag = cmSystemTools::OUTPUT_FORWARD;
}
// should we do a clean first?
if (clean) {
- GeneratedMakeCommand cleanCommand;
- this->GenerateBuildCommand(cleanCommand, makeCommandCSTR, projectName,
- bindir, "clean", config, fast, jobs, verbose);
+ std::vector<GeneratedMakeCommand> cleanCommand =
+ this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir,
+ { "clean" }, config, fast, jobs, verbose);
output += "\nRun Clean Command:";
- output += cleanCommand.printable();
+ output += cleanCommand.front().Printable();
output += "\n";
-
- if (!cmSystemTools::RunSingleCommand(cleanCommand.PrimaryCommand,
+ if (cleanCommand.size() != 1) {
+ this->GetCMakeInstance()->IssueMessage(MessageType::INTERNAL_ERROR,
+ "The generator did not produce "
+ "exactly one command for the "
+ "'clean' target");
+ return 1;
+ }
+ if (!cmSystemTools::RunSingleCommand(cleanCommand.front().PrimaryCommand,
outputPtr, outputPtr, &retVal,
nullptr, outputflag, timeout)) {
cmSystemTools::SetRunCommandHideConsole(hideconsole);
@@ -1837,33 +1897,34 @@ int cmGlobalGenerator::Build(int jobs, const std::string& /*unused*/,
}
// now build
- std::string makeCommandStr = makeCommand.printable();
+ std::string makeCommandStr;
output += "\nRun Build Command(s):";
- output += makeCommandStr;
- output += "\n";
- if (!cmSystemTools::RunSingleCommand(makeCommand.PrimaryCommand, outputPtr,
- outputPtr, &retVal, nullptr, outputflag,
- timeout)) {
- cmSystemTools::SetRunCommandHideConsole(hideconsole);
- cmSystemTools::Error(
- "Generator: execution of make failed. Make command was: ",
- makeCommandStr.c_str());
- output += *outputPtr;
- output += "\nGenerator: execution of make failed. Make command was: " +
- makeCommandStr + "\n";
+ for (auto command = makeCommand.begin(); command != makeCommand.end();
+ ++command) {
+ makeCommandStr = command->Printable();
+ if (command != makeCommand.end()) {
+ makeCommandStr += " && ";
+ }
- return 1;
- }
- output += *outputPtr;
- cmSystemTools::SetRunCommandHideConsole(hideconsole);
+ output += makeCommandStr;
+ if (!cmSystemTools::RunSingleCommand(command->PrimaryCommand, outputPtr,
+ outputPtr, &retVal, nullptr,
+ outputflag, timeout)) {
+ cmSystemTools::SetRunCommandHideConsole(hideconsole);
+ cmSystemTools::Error(
+ "Generator: execution of make failed. Make command was: " +
+ makeCommandStr);
+ output += *outputPtr;
+ output += "\nGenerator: execution of make failed. Make command was: " +
+ makeCommandStr + "\n";
- // The SGI MipsPro 7.3 compiler does not return an error code when
- // the source has a #error in it! This is a work-around for such
- // compilers.
- if ((retVal == 0) && (output.find("#error") != std::string::npos)) {
- retVal = 1;
+ return 1;
+ }
+ output += *outputPtr;
}
+ output += "\n";
+ cmSystemTools::SetRunCommandHideConsole(hideconsole);
// The OpenWatcom tools do not return an error code when a link
// library is not found!
@@ -2029,18 +2090,10 @@ bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
return this->IsExcluded(rootSnp, snp);
}
-bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
- cmGeneratorTarget* target) const
+bool cmGlobalGenerator::IsExcluded(cmGeneratorTarget* target) const
{
- if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
- return true;
- }
- if (const char* exclude = target->GetProperty("EXCLUDE_FROM_ALL")) {
- return cmSystemTools::IsOn(exclude);
- }
- // This target is included in its directory. Check whether the
- // directory is excluded.
- return this->IsExcluded(root, target->GetLocalGenerator());
+ return target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ target->GetPropertyAsBool("EXCLUDE_FROM_ALL");
}
void cmGlobalGenerator::GetEnabledLanguages(
@@ -2051,8 +2104,7 @@ void cmGlobalGenerator::GetEnabledLanguages(
int cmGlobalGenerator::GetLinkerPreference(const std::string& lang) const
{
- std::map<std::string, int>::const_iterator it =
- this->LanguageToLinkerPreference.find(lang);
+ auto const it = this->LanguageToLinkerPreference.find(lang);
if (it != this->LanguageToLinkerPreference.end()) {
return it->second;
}
@@ -2079,9 +2131,9 @@ void cmGlobalGenerator::FillProjectMap()
cmMakefile* cmGlobalGenerator::FindMakefile(const std::string& start_dir) const
{
- MakefileMap::const_iterator i = this->MakefileSearchIndex.find(start_dir);
- if (i != this->MakefileSearchIndex.end()) {
- return i->second;
+ auto const it = this->MakefileSearchIndex.find(start_dir);
+ if (it != this->MakefileSearchIndex.end()) {
+ return it->second;
}
return nullptr;
}
@@ -2089,10 +2141,9 @@ cmMakefile* cmGlobalGenerator::FindMakefile(const std::string& start_dir) const
cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(
cmDirectoryId const& id) const
{
- LocalGeneratorMap::const_iterator i =
- this->LocalGeneratorSearchIndex.find(id.String);
- if (i != this->LocalGeneratorSearchIndex.end()) {
- return i->second;
+ auto const it = this->LocalGeneratorSearchIndex.find(id.String);
+ if (it != this->LocalGeneratorSearchIndex.end()) {
+ return it->second;
}
return nullptr;
}
@@ -2122,17 +2173,24 @@ void cmGlobalGenerator::IndexGeneratorTarget(cmGeneratorTarget* gt)
}
}
+static char const hexDigits[] = "0123456789abcdef";
+
std::string cmGlobalGenerator::IndexGeneratorTargetUniquely(
cmGeneratorTarget const* gt)
{
// Use the pointer value to uniquely identify the target instance.
- // Use a "T" prefix to indicate that this identifier is for a target.
+ // Use a ":" prefix to avoid conflict with project-defined targets.
// We must satisfy cmGeneratorExpression::IsValidTargetName so use no
// other special characters.
- char buf[64];
- sprintf(buf, "::T%p",
- static_cast<void const*>(gt)); // cast avoids format warning
- std::string id = gt->GetName() + buf;
+ char buf[1 + sizeof(gt) * 2];
+ char* b = buf;
+ *b++ = ':';
+ for (size_t i = 0; i < sizeof(gt); ++i) {
+ unsigned char const c = reinterpret_cast<unsigned char const*>(&gt)[i];
+ *b++ = hexDigits[(c & 0xf0) >> 4];
+ *b++ = hexDigits[(c & 0x0f)];
+ }
+ std::string id(buf, sizeof(buf));
// We internally index pointers to non-const generator targets
// but our callers only have pointers to const generator targets.
// They will give up non-const privileges when looking up anyway.
@@ -2159,9 +2217,9 @@ void cmGlobalGenerator::IndexLocalGenerator(cmLocalGenerator* lg)
cmTarget* cmGlobalGenerator::FindTargetImpl(std::string const& name) const
{
- TargetMap::const_iterator i = this->TargetSearchIndex.find(name);
- if (i != this->TargetSearchIndex.end()) {
- return i->second;
+ auto const it = this->TargetSearchIndex.find(name);
+ if (it != this->TargetSearchIndex.end()) {
+ return it->second;
}
return nullptr;
}
@@ -2169,10 +2227,9 @@ cmTarget* cmGlobalGenerator::FindTargetImpl(std::string const& name) const
cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTargetImpl(
std::string const& name) const
{
- GeneratorTargetMap::const_iterator i =
- this->GeneratorTargetSearchIndex.find(name);
- if (i != this->GeneratorTargetSearchIndex.end()) {
- return i->second;
+ auto const it = this->GeneratorTargetSearchIndex.find(name);
+ if (it != this->GeneratorTargetSearchIndex.end()) {
+ return it->second;
}
return nullptr;
}
@@ -2181,8 +2238,7 @@ cmTarget* cmGlobalGenerator::FindTarget(const std::string& name,
bool excludeAliases) const
{
if (!excludeAliases) {
- std::map<std::string, std::string>::const_iterator ai =
- this->AliasTargets.find(name);
+ auto const ai = this->AliasTargets.find(name);
if (ai != this->AliasTargets.end()) {
return this->FindTargetImpl(ai->second);
}
@@ -2193,8 +2249,7 @@ cmTarget* cmGlobalGenerator::FindTarget(const std::string& name,
cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTarget(
const std::string& name) const
{
- std::map<std::string, std::string>::const_iterator ai =
- this->AliasTargets.find(name);
+ auto const ai = this->AliasTargets.find(name);
if (ai != this->AliasTargets.end()) {
return this->FindGeneratorTargetImpl(ai->second);
}
@@ -2204,7 +2259,7 @@ cmGeneratorTarget* cmGlobalGenerator::FindGeneratorTarget(
bool cmGlobalGenerator::NameResolvesToFramework(
const std::string& libname) const
{
- if (cmSystemTools::IsPathToFramework(libname.c_str())) {
+ if (cmSystemTools::IsPathToFramework(libname)) {
return true;
}
@@ -2285,10 +2340,9 @@ void cmGlobalGenerator::AddGlobalTarget_Package(
return;
}
- const char* reservedTargets[] = { "package", "PACKAGE" };
- for (const char* const* tn = cm::cbegin(reservedTargets);
- tn != cm::cend(reservedTargets); ++tn) {
- if (!this->CheckCMP0037(*tn, "when CPack packaging is enabled")) {
+ static const auto reservedTargets = { "package", "PACKAGE" };
+ for (auto const& target : reservedTargets) {
+ if (!this->CheckCMP0037(target, "when CPack packaging is enabled")) {
return;
}
}
@@ -2335,10 +2389,10 @@ void cmGlobalGenerator::AddGlobalTarget_PackageSource(
return;
}
- const char* reservedTargets[] = { "package_source" };
- for (const char* const* tn = cm::cbegin(reservedTargets);
- tn != cm::cend(reservedTargets); ++tn) {
- if (!this->CheckCMP0037(*tn, "when CPack source packaging is enabled")) {
+ static const auto reservedTargets = { "package_source" };
+ for (auto const& target : reservedTargets) {
+ if (!this->CheckCMP0037(target,
+ "when CPack source packaging is enabled")) {
return;
}
}
@@ -2365,10 +2419,9 @@ void cmGlobalGenerator::AddGlobalTarget_Test(
return;
}
- const char* reservedTargets[] = { "test", "RUN_TESTS" };
- for (const char* const* tn = cm::cbegin(reservedTargets);
- tn != cm::cend(reservedTargets); ++tn) {
- if (!this->CheckCMP0037(*tn, "when CTest testing is enabled")) {
+ static const auto reservedTargets = { "test", "RUN_TESTS" };
+ for (auto const& target : reservedTargets) {
+ if (!this->CheckCMP0037(target, "when CTest testing is enabled")) {
return;
}
}
@@ -2627,8 +2680,7 @@ bool cmGlobalGenerator::ShouldStripResourcePath(cmMakefile* mf) const
std::string cmGlobalGenerator::GetSharedLibFlagsForLanguage(
std::string const& l) const
{
- std::map<std::string, std::string>::const_iterator it =
- this->LanguageToOriginalSharedLibFlags.find(l);
+ auto const it = this->LanguageToOriginalSharedLibFlags.find(l);
if (it != this->LanguageToOriginalSharedLibFlags.end()) {
return it->second;
}
@@ -2706,11 +2758,8 @@ void cmGlobalGenerator::GetTargetSets(TargetDependSet& projectTargets,
if (this->IsExcluded(root, generator)) {
continue;
}
- // Get the targets in the makefile
- const std::vector<cmGeneratorTarget*>& tgts =
- generator->GetGeneratorTargets();
- // loop over all the targets
- for (cmGeneratorTarget* target : tgts) {
+ // loop over all the generator targets in the makefile
+ for (cmGeneratorTarget* target : generator->GetGeneratorTargets()) {
if (this->IsRootOnlyTarget(target) &&
target->GetLocalGenerator() != root) {
continue;
@@ -2736,8 +2785,7 @@ void cmGlobalGenerator::AddTargetDepends(cmGeneratorTarget const* target,
if (projectTargets.insert(target).second) {
// This is the first time we have encountered the target.
// Recursively follow its dependencies.
- TargetDependSet const& ts = this->GetTargetDirectDepends(target);
- for (auto const& t : ts) {
+ for (auto const& t : this->GetTargetDirectDepends(target)) {
this->AddTargetDepends(t, projectTargets);
}
}
@@ -2849,8 +2897,7 @@ void cmGlobalGenerator::CheckRuleHashes(std::string const& pfile,
fname = line.substr(33);
// Look for a hash for this file's rule.
- std::map<std::string, RuleHash>::const_iterator rhi =
- this->RuleHashes.find(fname);
+ auto const rhi = this->RuleHashes.find(fname);
if (rhi != this->RuleHashes.end()) {
// Compare the rule hash in the file to that we were given.
if (strncmp(line.c_str(), rhi->second.Data, 32) != 0) {
@@ -2900,8 +2947,7 @@ void cmGlobalGenerator::WriteSummary()
cmGeneratedFileStream fout(fname);
for (cmLocalGenerator* lg : this->LocalGenerators) {
- const std::vector<cmGeneratorTarget*>& tgts = lg->GetGeneratorTargets();
- for (cmGeneratorTarget* tgt : tgts) {
+ for (cmGeneratorTarget* tgt : lg->GetGeneratorTargets()) {
if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
@@ -2989,12 +3035,9 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target)
for (std::string const& c : configs) {
target->GetSourceFiles(sources, c);
}
- std::vector<cmSourceFile*>::const_iterator sourcesEnd =
- cmRemoveDuplicates(sources);
- for (std::vector<cmSourceFile*>::const_iterator si = sources.begin();
- si != sourcesEnd; ++si) {
+ auto const sourcesEnd = cmRemoveDuplicates(sources);
+ for (cmSourceFile* sf : cmMakeRange(sources.cbegin(), sourcesEnd)) {
Json::Value& lj_source = lj_sources.append(Json::objectValue);
- cmSourceFile* sf = *si;
std::string const& sfp = sf->GetFullPath();
fout << sfp << "\n";
lj_source["file"] = sfp;
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 0e40610d4..db964892a 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -13,6 +13,7 @@
#include <utility>
#include <vector>
+#include "cmAlgorithms.h"
#include "cmCustomCommandLines.h"
#include "cmDuration.h"
#include "cmExportSetMap.h"
@@ -56,33 +57,20 @@ struct GeneratedMakeCommand
{
// Add each argument as a separate element to the vector
template <typename... T>
- void add(T&&... args)
+ void Add(T&&... args)
{
// iterate the args and append each one
AppendStrs(PrimaryCommand, std::forward<T>(args)...);
}
// Add each value in the iterators as a separate element to the vector
- void add(std::vector<std::string>::const_iterator start,
+ void Add(std::vector<std::string>::const_iterator start,
std::vector<std::string>::const_iterator end)
{
- PrimaryCommand.insert(PrimaryCommand.end(), start, end);
+ cmAppend(PrimaryCommand, start, end);
}
- std::string printable() const
- {
- std::size_t size = PrimaryCommand.size();
- for (auto&& i : PrimaryCommand) {
- size += i.size();
- }
- std::string buffer;
- buffer.reserve(size);
- for (auto&& i : PrimaryCommand) {
- buffer.append(i);
- buffer.append(1, ' ');
- }
- return buffer;
- }
+ std::string Printable() const { return cmJoin(PrimaryCommand, " "); }
std::vector<std::string> PrimaryCommand;
bool RequiresOutputForward = false;
@@ -98,13 +86,13 @@ struct GeneratedMakeCommand
class cmGlobalGenerator
{
public:
- ///! Free any memory allocated with the GlobalGenerator
+ //! Free any memory allocated with the GlobalGenerator
cmGlobalGenerator(cmake* cm);
virtual ~cmGlobalGenerator();
virtual cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf);
- ///! Get the name for this generator
+ //! Get the name for this generator
virtual std::string GetName() const { return "Generic"; }
/** Check whether the given name matches the current generator. */
@@ -216,10 +204,10 @@ public:
*/
int Build(
int jobs, const std::string& srcdir, const std::string& bindir,
- const std::string& projectName, const std::string& targetName,
- std::string& output, const std::string& makeProgram,
- const std::string& config, bool clean, bool fast, bool verbose,
- cmDuration timeout,
+ const std::string& projectName,
+ std::vector<std::string> const& targetNames, std::string& output,
+ const std::string& makeProgram, const std::string& config, bool clean,
+ bool fast, bool verbose, cmDuration timeout,
cmSystemTools::OutputOption outputflag = cmSystemTools::OUTPUT_NONE,
std::vector<std::string> const& nativeOptions =
std::vector<std::string>());
@@ -234,11 +222,10 @@ public:
{
};
- virtual void GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& projectDir,
- const std::string& targetName, const std::string& config, bool fast,
- int jobs, bool verbose,
+ virtual std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
std::vector<std::string> const& makeOptions = std::vector<std::string>());
virtual void PrintBuildCommandAdvice(std::ostream& os, int jobs) const;
@@ -249,7 +236,7 @@ public:
const std::string& native,
bool ignoreErrors);
- ///! Get the CMake instance
+ //! Get the CMake instance
cmake* GetCMakeInstance() const { return this->CMakeInstance; }
void SetConfiguredFilesPath(cmGlobalGenerator* gen);
@@ -274,7 +261,7 @@ public:
void AddMakefile(cmMakefile* mf);
- ///! Set an generator for an "external makefile based project"
+ //! Set an generator for an "external makefile based project"
void SetExternalMakefileProjectGenerator(
cmExternalMakefileProjectGenerator* extraGenerator);
@@ -303,19 +290,19 @@ public:
bool GetForceUnixPaths() const { return this->ForceUnixPaths; }
bool GetToolSupportsColor() const { return this->ToolSupportsColor; }
- ///! return the language for the given extension
+ //! return the language for the given extension
std::string GetLanguageFromExtension(const char* ext) const;
- ///! is an extension to be ignored
+ //! is an extension to be ignored
bool IgnoreFile(const char* ext) const;
- ///! What is the preference for linkers and this language (None or Preferred)
+ //! What is the preference for linkers and this language (None or Preferred)
int GetLinkerPreference(const std::string& lang) const;
- ///! What is the object file extension for a given source file?
+ //! What is the object file extension for a given source file?
std::string GetLanguageOutputExtension(cmSourceFile const&) const;
- ///! What is the configurations directory variable called?
+ //! What is the configurations directory variable called?
virtual const char* GetCMakeCFGIntDir() const { return "."; }
- ///! expand CFGIntDir for a configuration
+ //! expand CFGIntDir for a configuration
virtual std::string ExpandCFGIntDir(const std::string& str,
const std::string& config) const;
@@ -331,7 +318,7 @@ public:
*/
virtual bool FindMakeProgram(cmMakefile*);
- ///! Find a target by name by searching the local generators.
+ //! Find a target by name by searching the local generators.
cmTarget* FindTarget(const std::string& name,
bool excludeAliases = false) const;
@@ -522,7 +509,7 @@ protected:
bool IsExcluded(cmStateSnapshot const& root,
cmStateSnapshot const& snp) const;
bool IsExcluded(cmLocalGenerator* root, cmLocalGenerator* gen) const;
- bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target) const;
+ bool IsExcluded(cmGeneratorTarget* target) const;
virtual void InitializeProgressMarks() {}
struct GlobalTargetInfo
@@ -622,6 +609,7 @@ private:
virtual void ForceLinkerLanguages();
bool CheckTargetsForMissingSources() const;
+ bool CheckTargetsForType() const;
void CreateLocalGenerators();
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index 45fa0529f..b69dea038 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -2,22 +2,33 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGlobalGhsMultiGenerator.h"
-#include "cmsys/SystemTools.hxx"
-
-#include "cmAlgorithms.h"
#include "cmDocumentationEntry.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
-#include "cmGhsMultiTargetGenerator.h"
+#include "cmGhsMultiGpj.h"
+#include "cmLocalGenerator.h"
#include "cmLocalGhsMultiGenerator.h"
#include "cmMakefile.h"
#include "cmState.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
#include "cmVersion.h"
#include "cmake.h"
+#include <algorithm>
+#include <map>
+#include <ostream>
+#include <string.h>
+#include <utility>
+
const char* cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj";
+#ifdef __linux__
+const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild";
+const char* cmGlobalGhsMultiGenerator::DEFAULT_TOOLSET_ROOT = "/usr/ghs";
+#elif defined(_WIN32)
const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild.exe";
const char* cmGlobalGhsMultiGenerator::DEFAULT_TOOLSET_ROOT = "C:/ghs";
+#endif
cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm)
: cmGlobalGenerator(cm)
@@ -25,9 +36,7 @@ cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm)
cm->GetState()->SetGhsMultiIDE(true);
}
-cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator()
-{
-}
+cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator() = default;
cmLocalGenerator* cmGlobalGhsMultiGenerator::CreateLocalGenerator(
cmMakefile* mf)
@@ -64,7 +73,8 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
/* no toolset was found */
if (tsp.empty()) {
return false;
- } else if (ts.empty()) {
+ }
+ if (ts.empty()) {
std::string message;
message =
"Green Hills MULTI: -T <toolset> not specified; defaulting to \"";
@@ -86,7 +96,7 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
const char* prevTool = mf->GetDefinition("CMAKE_MAKE_PROGRAM");
/* check if the toolset changed from last generate */
- if (prevTool != NULL && (gbuild != prevTool)) {
+ if (prevTool != nullptr && (gbuild != prevTool)) {
std::string message = "toolset build tool: ";
message += gbuild;
message += "\nDoes not match the previously used build tool: ";
@@ -95,13 +105,12 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
"directory or choose a different binary directory.";
cmSystemTools::Error(message);
return false;
- } else {
- /* store the toolset that is being used for this build */
- mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild.c_str(),
- "build program to use", cmStateEnums::INTERNAL,
- true);
}
+ /* store the toolset that is being used for this build */
+ mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild.c_str(),
+ "build program to use", cmStateEnums::INTERNAL, true);
+
mf->AddDefinition("CMAKE_SYSTEM_VERSION", tsp.c_str());
return true;
@@ -110,10 +119,11 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p,
cmMakefile* mf)
{
- if (p == "") {
+ std::string arch;
+ if (p.empty()) {
cmSystemTools::Message(
"Green Hills MULTI: -A <arch> not specified; defaulting to \"arm\"");
- std::string arch = "arm";
+ arch = "arm";
/* store the platform name for later use
* -- already done if -A<arch> was specified
@@ -121,19 +131,51 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p,
mf->AddCacheDefinition("CMAKE_GENERATOR_PLATFORM", arch.c_str(),
"Name of generator platform.",
cmStateEnums::INTERNAL);
+ } else {
+ arch = p;
}
- const char* tgtPlatform = mf->GetDefinition("GHS_TARGET_PLATFORM");
- if (tgtPlatform == nullptr) {
- cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not "
- "specified; defaulting to \"integrity\"");
- tgtPlatform = "integrity";
+ /* check if OS location has been updated by platform scripts */
+ std::string platform = mf->GetSafeDefinition("GHS_TARGET_PLATFORM");
+ std::string osdir = mf->GetSafeDefinition("GHS_OS_DIR");
+ if (cmSystemTools::IsOff(osdir.c_str()) &&
+ platform.find("integrity") != std::string::npos) {
+ if (!this->CMakeInstance->GetIsInTryCompile()) {
+ /* required OS location is not found */
+ std::string m =
+ "Green Hills MULTI: GHS_OS_DIR not specified; No OS found in \"";
+ m += mf->GetSafeDefinition("GHS_OS_ROOT");
+ m += "\"";
+ cmSystemTools::Message(m);
+ }
+ osdir = "GHS_OS_DIR-NOT-SPECIFIED";
+ } else if (!this->CMakeInstance->GetIsInTryCompile() &&
+ cmSystemTools::IsOff(this->OsDir) &&
+ !cmSystemTools::IsOff(osdir)) {
+ /* OS location was updated by auto-selection */
+ std::string m = "Green Hills MULTI: GHS_OS_DIR not specified; found \"";
+ m += osdir;
+ m += "\"";
+ cmSystemTools::Message(m);
}
+ this->OsDir = osdir;
- /* store the platform name for later use */
- mf->AddCacheDefinition("GHS_TARGET_PLATFORM", tgtPlatform,
- "Name of GHS target platform.",
- cmStateEnums::INTERNAL);
+ // Determine GHS_BSP_NAME
+ std::string bspName = mf->GetSafeDefinition("GHS_BSP_NAME");
+
+ if (cmSystemTools::IsOff(bspName.c_str()) &&
+ platform.find("integrity") != std::string::npos) {
+ bspName = "sim" + arch;
+ /* write back the calculate name for next time */
+ mf->AddCacheDefinition("GHS_BSP_NAME", bspName.c_str(),
+ "Name of GHS target platform.",
+ cmStateEnums::STRING, true);
+ std::string m =
+ "Green Hills MULTI: GHS_BSP_NAME not specified; defaulting to \"";
+ m += bspName;
+ m += "\"";
+ cmSystemTools::Message(m);
+ }
return true;
}
@@ -144,6 +186,21 @@ void cmGlobalGhsMultiGenerator::EnableLanguage(
mf->AddDefinition("CMAKE_SYSTEM_NAME", "GHS-MULTI");
mf->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files
+
+ const char* tgtPlatform = mf->GetDefinition("GHS_TARGET_PLATFORM");
+ if (!tgtPlatform) {
+ cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not "
+ "specified; defaulting to \"integrity\"");
+ tgtPlatform = "integrity";
+ }
+
+ /* store the platform name for later use */
+ mf->AddCacheDefinition("GHS_TARGET_PLATFORM", tgtPlatform,
+ "Name of GHS target platform.", cmStateEnums::STRING);
+
+ /* store original OS location */
+ this->OsDir = mf->GetSafeDefinition("GHS_OS_DIR");
+
this->cmGlobalGenerator::EnableLanguage(l, mf, optional);
}
@@ -185,8 +242,7 @@ void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile* mf, std::string& tsd,
}
} else {
std::string tryPath;
- /* CollapseCombinedPath will check if ts is an absolute path */
- tryPath = cmSystemTools::CollapseCombinedPath(tsd, ts);
+ tryPath = cmSystemTools::CollapseFullPath(ts, tsd);
if (!cmSystemTools::FileExists(tryPath)) {
std::string msg = "GHS toolset \"" + tryPath + "\" not found.";
cmSystemTools::Error(msg);
@@ -202,139 +258,246 @@ void cmGlobalGhsMultiGenerator::WriteFileHeader(std::ostream& fout)
fout << "#!gbuild" << std::endl;
fout << "#" << std::endl
<< "# CMAKE generated file: DO NOT EDIT!" << std::endl
- << "# Generated by \"" << this->GetActualName() << "\""
+ << "# Generated by \"" << GetActualName() << "\""
<< " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
<< cmVersion::GetMinorVersion() << std::endl
<< "#" << std::endl
<< std::endl;
}
-void cmGlobalGhsMultiGenerator::WriteTopLevelProject(
- std::ostream& fout, cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators)
+void cmGlobalGhsMultiGenerator::WriteCustomRuleBOD(std::ostream& fout)
{
- WriteFileHeader(fout);
+ fout << "Commands {\n"
+ " Custom_Rule_Command {\n"
+ " name = \"Custom Rule Command\"\n"
+ " exec = \"";
+#ifdef _WIN32
+ fout << "cmd.exe";
+#else
+ fout << "/bin/sh";
+#endif
+ fout << "\"\n"
+ " options = {\"SpecialOptions\"}\n"
+ " }\n"
+ "}\n";
+
+ fout << "\n\n";
+ fout << "FileTypes {\n"
+ " CmakeRule {\n"
+ " name = \"Custom Rule\"\n"
+ " action = \"&Run\"\n"
+ " extensions = {\"";
+#ifdef _WIN32
+ fout << "bat";
+#else
+ fout << "sh";
+#endif
+ fout << "\"}\n"
+ " grepable = false\n"
+ " command = \"Custom Rule Command\"\n"
+ " commandLine = \"$COMMAND ";
+#ifdef _WIN32
+ fout << "/c";
+#endif
+ fout << " $INPUTFILE\"\n"
+ " progress = \"Processing Custom Rule\"\n"
+ " promoteToFirstPass = true\n"
+ " outputType = \"None\"\n"
+ " color = \"#800080\"\n"
+ " }\n"
+ "}\n";
+}
+
+void cmGlobalGhsMultiGenerator::WriteCustomTargetBOD(std::ostream& fout)
+{
+ fout << "FileTypes {\n"
+ " CmakeTarget {\n"
+ " name = \"Custom Target\"\n"
+ " action = \"&Execute\"\n"
+ " grepable = false\n"
+ " outputType = \"None\"\n"
+ " color = \"#800080\"\n"
+ " }\n"
+ "}\n";
+}
- this->WriteMacros(fout);
- this->WriteHighLevelDirectives(fout);
+void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout,
+ cmLocalGenerator* root)
+{
+ this->WriteFileHeader(fout);
+ this->WriteMacros(fout, root);
+ this->WriteHighLevelDirectives(root, fout);
GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fout);
fout << "# Top Level Project File" << std::endl;
// Specify BSP option if supplied by user
- // -- not all platforms require this entry in the project file
- // integrity platforms require this field; use default if needed
- std::string platform;
- if (const char* p =
- this->GetCMakeInstance()->GetCacheDefinition("GHS_TARGET_PLATFORM")) {
- platform = p;
- }
-
- std::string bspName;
- if (char const* bspCache =
- this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME")) {
- bspName = bspCache;
- this->GetCMakeInstance()->MarkCliAsUsed("GHS_BSP_NAME");
- } else {
- bspName = "IGNORE";
- }
-
- if (platform.find("integrity") != std::string::npos &&
- cmSystemTools::IsOff(bspName.c_str())) {
- const char* a =
- this->GetCMakeInstance()->GetCacheDefinition("CMAKE_GENERATOR_PLATFORM");
- bspName = "sim";
- bspName += (a ? a : "");
- }
-
- if (!cmSystemTools::IsOff(bspName.c_str())) {
+ const char* bspName =
+ this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME");
+ if (!cmSystemTools::IsOff(bspName)) {
fout << " -bsp " << bspName << std::endl;
}
// Specify OS DIR if supplied by user
// -- not all platforms require this entry in the project file
- std::string osDir;
- std::string osDirOption;
- if (char const* osDirCache =
- this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR")) {
- osDir = osDirCache;
+ if (!cmSystemTools::IsOff(this->OsDir.c_str())) {
+ const char* osDirOption =
+ this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR_OPTION");
+ std::replace(this->OsDir.begin(), this->OsDir.end(), '\\', '/');
+ fout << " ";
+ if (cmSystemTools::IsOff(osDirOption)) {
+ fout << "";
+ } else {
+ fout << osDirOption;
+ }
+ fout << "\"" << this->OsDir << "\"" << std::endl;
}
+}
- if (char const* osDirOptionCache =
- this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR_OPTION")) {
- osDirOption = osDirOptionCache;
+void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream& fout,
+ std::string& all_target)
+{
+ fout << "CMakeFiles/" << all_target << " [Project]" << std::endl;
+ // All known targets
+ for (cmGeneratorTarget const* target : this->ProjectTargets) {
+ if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
+ target->GetName() != GetInstallTargetName())) {
+ continue;
+ }
+ fout << "CMakeFiles/" << target->GetName() + ".tgt" + FILE_EXTENSION
+ << " [Project]" << std::endl;
}
+}
- if (!cmSystemTools::IsOff(osDir.c_str()) ||
- platform.find("integrity") != std::string::npos) {
- std::replace(osDir.begin(), osDir.end(), '\\', '/');
- fout << " " << osDirOption << "\"" << osDir << "\"" << std::endl;
+void cmGlobalGhsMultiGenerator::WriteProjectLine(
+ std::ostream& fout, cmGeneratorTarget const* target, cmLocalGenerator* root,
+ std::string& rootBinaryDir)
+{
+ const char* projName = target->GetProperty("GENERATOR_FILE_NAME");
+ const char* projType = target->GetProperty("GENERATOR_FILE_NAME_EXT");
+ if (projName && projType) {
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ std::string dir = lg->GetCurrentBinaryDirectory();
+ dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir);
+ if (dir == ".") {
+ dir.clear();
+ } else {
+ if (dir.back() != '/') {
+ dir += "/";
+ }
+ }
+
+ std::string projFile = dir + projName + FILE_EXTENSION;
+ fout << projFile;
+ fout << " " << projType << std::endl;
+ } else {
+ /* Should never happen */
+ std::string message =
+ "The project file for target [" + target->GetName() + "] is missing.\n";
+ cmSystemTools::Error(message);
+ fout << "{comment} " << target->GetName() << " [missing project file]\n";
}
+}
+
+void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator* root)
+{
+ std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
+ rootBinaryDir += "/CMakeFiles";
+
+ // All known targets
+ for (cmGeneratorTarget const* target : this->ProjectTargets) {
+ if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
+ target->GetName() != GetInstallTargetName())) {
+ continue;
+ }
- WriteSubProjects(fout, root, generators);
+ // create target build file
+ std::string name = target->GetName() + ".tgt" + FILE_EXTENSION;
+ std::string fname = rootBinaryDir + "/" + name;
+ cmGeneratedFileStream fbld(fname);
+ fbld.SetCopyIfDifferent(true);
+ this->WriteFileHeader(fbld);
+ GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld);
+ std::vector<cmGeneratorTarget const*> build;
+ if (ComputeTargetBuildOrder(target, build)) {
+ std::string message = "The inter-target dependency graph for target [" +
+ target->GetName() + "] had a cycle.\n";
+ cmSystemTools::Error(message);
+ } else {
+ for (auto& tgt : build) {
+ WriteProjectLine(fbld, tgt, root, rootBinaryDir);
+ }
+ }
+ fbld.Close();
+ }
}
-void cmGlobalGhsMultiGenerator::WriteSubProjects(
- std::ostream& fout, cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators)
+void cmGlobalGhsMultiGenerator::WriteAllTarget(
+ cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators,
+ std::string& all_target)
{
+ this->ProjectTargets.clear();
+
+ // create target build file
+ all_target = root->GetProjectName() + "." + this->GetAllTargetName() +
+ ".tgt" + FILE_EXTENSION;
+ std::string fname =
+ root->GetCurrentBinaryDirectory() + "/CMakeFiles/" + all_target;
+ cmGeneratedFileStream fbld(fname);
+ fbld.SetCopyIfDifferent(true);
+ this->WriteFileHeader(fbld);
+ GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld);
+
// Collect all targets under this root generator and the transitive
// closure of their dependencies.
TargetDependSet projectTargets;
TargetDependSet originalTargets;
this->GetTargetSets(projectTargets, originalTargets, root, generators);
- OrderedTargetDependSet orderedProjectTargets(projectTargets, "");
-
- // write out all the sub-projects
- std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
- for (cmGeneratorTarget const* target : orderedProjectTargets) {
- if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ OrderedTargetDependSet sortedProjectTargets(projectTargets, "");
+ std::vector<cmGeneratorTarget const*> defaultTargets;
+ for (cmGeneratorTarget const* t : sortedProjectTargets) {
+ /* save list of all targets in sorted order */
+ this->ProjectTargets.push_back(t);
+ }
+ for (cmGeneratorTarget const* t : sortedProjectTargets) {
+ if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
-
- const char* projName = target->GetProperty("GENERATOR_FILE_NAME");
- const char* projType = target->GetProperty("GENERATOR_FILE_NAME_EXT");
- if (projName && projType) {
- cmLocalGenerator* lg = target->GetLocalGenerator();
- std::string dir = lg->GetCurrentBinaryDirectory();
- dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir.c_str());
- if (dir == ".") {
- dir.clear();
- } else {
- if (dir.back() != '/') {
- dir += "/";
- }
- }
-
- if (cmSystemTools::IsOn(target->GetProperty("EXCLUDE_FROM_ALL"))) {
- fout << "{comment} ";
- }
- std::string projFile = dir + projName + FILE_EXTENSION;
- fout << projFile;
- fout << " " << projType << std::endl;
-
- if (cmSystemTools::IsOn(target->GetProperty("GHS_REFERENCE_PROJECT"))) {
- // create reference project
- std::string fname = dir;
- fname += target->GetName();
- fname += "REF";
- fname += FILE_EXTENSION;
-
- cmGeneratedFileStream fref(fname.c_str());
- fref.SetCopyIfDifferent(true);
-
- this->WriteFileHeader(fref);
- GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fref);
- fref << " :reference=" << projFile << std::endl;
-
- fref.Close();
+ if (!cmSystemTools::IsOn(t->GetProperty("EXCLUDE_FROM_ALL"))) {
+ defaultTargets.push_back(t);
+ }
+ }
+ std::vector<cmGeneratorTarget const*> build;
+ if (ComputeTargetBuildOrder(defaultTargets, build)) {
+ std::string message = "The inter-target dependency graph for project [" +
+ root->GetProjectName() + "] had a cycle.\n";
+ cmSystemTools::Error(message);
+ } else {
+ // determine the targets for ALL target
+ std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
+ rootBinaryDir += "/CMakeFiles";
+ for (cmGeneratorTarget const* target : build) {
+ if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+ target->GetType() == cmStateEnums::MODULE_LIBRARY ||
+ target->GetType() == cmStateEnums::SHARED_LIBRARY) {
+ continue;
}
+ this->WriteProjectLine(fbld, target, root, rootBinaryDir);
}
}
+ fbld.Close();
}
void cmGlobalGhsMultiGenerator::Generate()
{
+ std::string fname;
+
// first do the superclass method
this->cmGlobalGenerator::Generate();
@@ -342,11 +505,32 @@ void cmGlobalGhsMultiGenerator::Generate()
for (auto& it : this->ProjectMap) {
this->OutputTopLevelProject(it.second[0], it.second);
}
+
+ // create custom rule BOD file
+ fname = this->GetCMakeInstance()->GetHomeOutputDirectory() +
+ "/CMakeFiles/custom_rule.bod";
+ cmGeneratedFileStream frule(fname);
+ frule.SetCopyIfDifferent(true);
+ this->WriteFileHeader(frule);
+ this->WriteCustomRuleBOD(frule);
+ frule.Close();
+
+ // create custom target BOD file
+ fname = this->GetCMakeInstance()->GetHomeOutputDirectory() +
+ "/CMakeFiles/custom_target.bod";
+ cmGeneratedFileStream ftarget(fname);
+ ftarget.SetCopyIfDifferent(true);
+ this->WriteFileHeader(ftarget);
+ this->WriteCustomTargetBOD(ftarget);
+ ftarget.Close();
}
void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
{
+ std::string fname;
+ std::string all_target;
+
if (generators.empty()) {
return;
}
@@ -355,86 +539,106 @@ void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
* with target projects. This avoid the issue where the project has
* the same name as the executable target.
*/
- std::string fname = root->GetCurrentBinaryDirectory();
+ fname = root->GetCurrentBinaryDirectory();
fname += "/";
fname += root->GetProjectName();
fname += ".top";
fname += FILE_EXTENSION;
- cmGeneratedFileStream fout(fname.c_str());
- fout.SetCopyIfDifferent(true);
+ cmGeneratedFileStream top(fname);
+ top.SetCopyIfDifferent(true);
+ this->WriteTopLevelProject(top, root);
- this->WriteTopLevelProject(fout, root, generators);
+ this->WriteAllTarget(root, generators, all_target);
+ this->WriteTargets(root);
- fout.Close();
+ this->WriteSubProjects(top, all_target);
+ top.Close();
}
-void cmGlobalGhsMultiGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& projectDir,
- const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
- int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalGhsMultiGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& /*config*/, bool /*fast*/, int jobs, bool /*verbose*/,
+ std::vector<std::string> const& makeOptions)
{
- const char* gbuild =
- this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
- makeCommand.add(this->SelectMakeProgram(makeProgram, (std::string)gbuild));
+ GeneratedMakeCommand makeCommand = {};
+ std::string gbuild;
+ if (const char* gbuildCached =
+ this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM")) {
+ gbuild = gbuildCached;
+ }
+ makeCommand.Add(this->SelectMakeProgram(makeProgram, gbuild));
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
- makeCommand.add("-parallel");
+ makeCommand.Add("-parallel");
if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
- makeCommand.add(std::to_string(jobs));
+ makeCommand.Add(std::to_string(jobs));
}
}
- makeCommand.add(makeOptions.begin(), makeOptions.end());
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
/* determine which top-project file to use */
std::string proj = projectName + ".top" + FILE_EXTENSION;
std::vector<std::string> files;
cmSystemTools::Glob(projectDir, ".*\\.top\\.gpj", files);
if (!files.empty()) {
+ /* if multiple top-projects are found in build directory
+ * then prefer projectName top-project.
+ */
auto p = std::find(files.begin(), files.end(), proj);
if (p == files.end()) {
proj = files.at(0);
}
}
- makeCommand.add("-top", proj);
- if (!targetName.empty()) {
- if (targetName == "clean") {
- makeCommand.add("-clean");
+ makeCommand.Add("-top", proj);
+ if (!targetNames.empty()) {
+ if (std::find(targetNames.begin(), targetNames.end(), "clean") !=
+ targetNames.end()) {
+ makeCommand.Add("-clean");
} else {
- if (targetName.compare(targetName.size() - 4, 4, ".gpj") == 0) {
- makeCommand.add(targetName);
- } else {
- makeCommand.add(targetName + ".gpj");
+ for (const auto& tname : targetNames) {
+ if (!tname.empty()) {
+ makeCommand.Add(tname + ".tgt.gpj");
+ }
}
}
+ } else {
+ /* transform name to default build */;
+ std::string all = proj;
+ all.replace(all.end() - 7, all.end(),
+ std::string(this->GetAllTargetName()) + ".tgt.gpj");
+ makeCommand.Add(all);
}
+ return { makeCommand };
}
-void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout)
+void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout,
+ cmLocalGenerator* root)
{
+ fout << "macro PROJ_NAME=" << root->GetProjectName() << std::endl;
char const* ghsGpjMacros =
this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS");
- if (NULL != ghsGpjMacros) {
+ if (nullptr != ghsGpjMacros) {
std::vector<std::string> expandedList;
cmSystemTools::ExpandListArgument(std::string(ghsGpjMacros), expandedList);
- for (std::vector<std::string>::const_iterator expandedListI =
- expandedList.begin();
- expandedListI != expandedList.end(); ++expandedListI) {
- fout << "macro " << *expandedListI << std::endl;
+ for (std::string const& arg : expandedList) {
+ fout << "macro " << arg << std::endl;
}
}
}
-void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(std::ostream& fout)
+void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(
+ cmLocalGenerator* root, std::ostream& fout)
{
/* set primary target */
std::string tgt;
const char* t =
this->GetCMakeInstance()->GetCacheDefinition("GHS_PRIMARY_TARGET");
- if (t) {
+ if (t && *t != '\0') {
tgt = t;
this->GetCMakeInstance()->MarkCliAsUsed("GHS_PRIMARY_TARGET");
} else {
@@ -449,16 +653,20 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(std::ostream& fout)
}
fout << "primaryTarget=" << tgt << std::endl;
+ fout << "customization=" << root->GetBinaryDirectory()
+ << "/CMakeFiles/custom_rule.bod" << std::endl;
+ fout << "customization=" << root->GetBinaryDirectory()
+ << "/CMakeFiles/custom_target.bod" << std::endl;
char const* const customization =
this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION");
- if (NULL != customization && strlen(customization) > 0) {
- fout << "customization=" << trimQuotes(customization) << std::endl;
+ if (nullptr != customization && strlen(customization) > 0) {
+ fout << "customization=" << this->TrimQuotes(customization) << std::endl;
this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
}
}
-std::string cmGlobalGhsMultiGenerator::trimQuotes(std::string const& str)
+std::string cmGlobalGhsMultiGenerator::TrimQuotes(std::string const& str)
{
std::string result;
result.reserve(str.size());
@@ -491,3 +699,56 @@ cmGlobalGhsMultiGenerator::OrderedTargetDependSet::OrderedTargetDependSet(
{
this->insert(targets.begin(), targets.end());
}
+
+bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
+ cmGeneratorTarget const* tgt, std::vector<cmGeneratorTarget const*>& build)
+{
+ std::vector<cmGeneratorTarget const*> t{ tgt };
+ return ComputeTargetBuildOrder(t, build);
+}
+
+bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
+ std::vector<cmGeneratorTarget const*>& tgt,
+ std::vector<cmGeneratorTarget const*>& build)
+{
+ std::set<cmGeneratorTarget const*> temp;
+ std::set<cmGeneratorTarget const*> perm;
+
+ for (auto ti : tgt) {
+ bool r = VisitTarget(temp, perm, build, ti);
+ if (r) {
+ return r;
+ }
+ }
+ return false;
+}
+
+bool cmGlobalGhsMultiGenerator::VisitTarget(
+ std::set<cmGeneratorTarget const*>& temp,
+ std::set<cmGeneratorTarget const*>& perm,
+ std::vector<cmGeneratorTarget const*>& order, cmGeneratorTarget const* ti)
+{
+ /* check if permanent mark is set*/
+ if (perm.find(ti) == perm.end()) {
+ /* set temporary mark; check if revisit*/
+ if (temp.insert(ti).second) {
+ /* sort targets lexicographically to ensure that nodes are always visited
+ * in the same order */
+ OrderedTargetDependSet sortedTargets(this->GetTargetDirectDepends(ti),
+ "");
+ for (auto& di : sortedTargets) {
+ if (this->VisitTarget(temp, perm, order, di)) {
+ return true;
+ }
+ }
+ /* mark as complete; insert into beginning of list*/
+ perm.insert(ti);
+ order.push_back(ti);
+ return false;
+ }
+ /* revisiting item - not a DAG */
+ return true;
+ }
+ /* already complete */
+ return false;
+}
diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h
index bc2b199a0..98358c74d 100644
--- a/Source/cmGlobalGhsMultiGenerator.h
+++ b/Source/cmGlobalGhsMultiGenerator.h
@@ -5,10 +5,20 @@
#include "cmGlobalGenerator.h"
-#include "cmGhsMultiGpj.h"
#include "cmGlobalGeneratorFactory.h"
+#include "cmTargetDepend.h"
-class cmGeneratedFileStream;
+#include <iosfwd>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+class cmGeneratorTarget;
+class cmLocalGenerator;
+class cmMakefile;
+class cmake;
+struct cmDocumentationEntry;
class cmGlobalGhsMultiGenerator : public cmGlobalGenerator
{
@@ -17,21 +27,21 @@ public:
static const char* FILE_EXTENSION;
cmGlobalGhsMultiGenerator(cmake* cm);
- ~cmGlobalGhsMultiGenerator();
+ ~cmGlobalGhsMultiGenerator() override;
static cmGlobalGeneratorFactory* NewFactory()
{
return new cmGlobalGeneratorSimpleFactory<cmGlobalGhsMultiGenerator>();
}
- ///! create the correct local generator
+ //! create the correct local generator
cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
/// @return the name of this generator.
static std::string GetActualName() { return "Green Hills MULTI"; }
- ///! Get the name for this generator
- std::string GetName() const override { return this->GetActualName(); }
+ //! Get the name for this generator
+ std::string GetName() const override { return GetActualName(); }
/// Overloaded methods. @see cmGlobalGenerator::GetDocumentation()
static void GetDocumentation(cmDocumentationEntry& entry);
@@ -68,7 +78,54 @@ public:
// Write the common disclaimer text at the top of each build file.
void WriteFileHeader(std::ostream& fout);
- // Target dependency sorting
+ const char* GetInstallTargetName() const override { return "install"; }
+
+protected:
+ void Generate() override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
+
+private:
+ void GetToolset(cmMakefile* mf, std::string& tsd, const std::string& ts);
+
+ /* top-level project */
+ void OutputTopLevelProject(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators);
+ void WriteTopLevelProject(std::ostream& fout, cmLocalGenerator* root);
+ void WriteMacros(std::ostream& fout, cmLocalGenerator* root);
+ void WriteHighLevelDirectives(cmLocalGenerator* root, std::ostream& fout);
+ void WriteSubProjects(std::ostream& fout, std::string& all_target);
+ void WriteTargets(cmLocalGenerator* root);
+ void WriteProjectLine(std::ostream& fout, cmGeneratorTarget const* target,
+ cmLocalGenerator* root, std::string& rootBinaryDir);
+ void WriteCustomRuleBOD(std::ostream& fout);
+ void WriteCustomTargetBOD(std::ostream& fout);
+ void WriteAllTarget(cmLocalGenerator* root,
+ std::vector<cmLocalGenerator*>& generators,
+ std::string& all_target);
+
+ std::string TrimQuotes(std::string const& str);
+
+ std::string OsDir;
+ static const char* DEFAULT_BUILD_PROGRAM;
+ static const char* DEFAULT_TOOLSET_ROOT;
+
+ bool ComputeTargetBuildOrder(cmGeneratorTarget const* tgt,
+ std::vector<cmGeneratorTarget const*>& build);
+ bool ComputeTargetBuildOrder(std::vector<cmGeneratorTarget const*>& tgt,
+ std::vector<cmGeneratorTarget const*>& build);
+ bool VisitTarget(std::set<cmGeneratorTarget const*>& temp,
+ std::set<cmGeneratorTarget const*>& perm,
+ std::vector<cmGeneratorTarget const*>& order,
+ cmGeneratorTarget const* ti);
+
+ std::vector<cmGeneratorTarget const*> ProjectTargets;
+
+ // Target sorting
class TargetSet : public std::set<cmGeneratorTarget const*>
{
};
@@ -77,44 +134,14 @@ public:
std::string First;
public:
- TargetCompare(std::string const& first)
- : First(first)
+ TargetCompare(std::string first)
+ : First(std::move(first))
{
}
bool operator()(cmGeneratorTarget const* l,
cmGeneratorTarget const* r) const;
};
class OrderedTargetDependSet;
-
-protected:
- void Generate() override;
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
-
-private:
- void GetToolset(cmMakefile* mf, std::string& tsd, const std::string& ts);
-
- /* top-level project */
- void OutputTopLevelProject(cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators);
- void WriteTopLevelProject(std::ostream& fout, cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators);
- void WriteMacros(std::ostream& fout);
- void WriteHighLevelDirectives(std::ostream& fout);
- void WriteSubProjects(std::ostream& fout, cmLocalGenerator* root,
- std::vector<cmLocalGenerator*>& generators);
-
- std::string trimQuotes(std::string const& str);
-
- static const char* DEFAULT_BUILD_PROGRAM;
- static const char* DEFAULT_TOOLSET_ROOT;
};
class cmGlobalGhsMultiGenerator::OrderedTargetDependSet
diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx
index 2b7f48695..ff5428868 100644
--- a/Source/cmGlobalJOMMakefileGenerator.cxx
+++ b/Source/cmGlobalJOMMakefileGenerator.cxx
@@ -54,19 +54,19 @@ void cmGlobalJOMMakefileGenerator::PrintCompilerAdvice(
this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
}
-void cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& projectDir,
- const std::string& targetName, const std::string& config, bool fast,
- int jobs, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions)
{
std::vector<std::string> jomMakeOptions;
// Since we have full control over the invocation of JOM, let us
// make it quiet.
jomMakeOptions.push_back(this->MakeSilentFlag);
- jomMakeOptions.insert(jomMakeOptions.end(), makeOptions.begin(),
- makeOptions.end());
+ cmAppend(jomMakeOptions, makeOptions);
// JOM does parallel builds by default, the -j is only needed if a specific
// number is given
@@ -75,7 +75,7 @@ void cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
}
- cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
- makeCommand, makeProgram, projectName, projectDir, targetName, config,
- fast, jobs, verbose, jomMakeOptions);
+ return cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast, jobs,
+ verbose, jomMakeOptions);
}
diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h
index aa8b5fbb0..df3aec9b4 100644
--- a/Source/cmGlobalJOMMakefileGenerator.h
+++ b/Source/cmGlobalJOMMakefileGenerator.h
@@ -20,7 +20,7 @@ public:
{
return new cmGlobalGeneratorSimpleFactory<cmGlobalJOMMakefileGenerator>();
}
- ///! Get the name for the generator.
+ //! Get the name for the generator.
std::string GetName() const override
{
return cmGlobalJOMMakefileGenerator::GetActualName();
@@ -40,15 +40,12 @@ public:
bool optional) override;
protected:
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
private:
void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
diff --git a/Source/cmGlobalMSYSMakefileGenerator.cxx b/Source/cmGlobalMSYSMakefileGenerator.cxx
index 3c2455662..7b5838909 100644
--- a/Source/cmGlobalMSYSMakefileGenerator.cxx
+++ b/Source/cmGlobalMSYSMakefileGenerator.cxx
@@ -45,9 +45,10 @@ void cmGlobalMSYSMakefileGenerator::EnableLanguage(
std::vector<std::string> const& l, cmMakefile* mf, bool optional)
{
this->FindMakeProgram(mf);
- std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& makeProgram =
+ mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
std::vector<std::string> locations;
- std::string makeloc = cmSystemTools::GetProgramPath(makeProgram.c_str());
+ std::string makeloc = cmSystemTools::GetProgramPath(makeProgram);
locations.push_back(this->FindMinGW(makeloc));
locations.push_back(makeloc);
locations.push_back("/mingw/bin");
@@ -76,8 +77,8 @@ void cmGlobalMSYSMakefileGenerator::EnableLanguage(
if (!mf->IsSet("CMAKE_AR") && !this->CMakeInstance->GetIsInTryCompile() &&
!(1 == l.size() && l[0] == "NONE")) {
cmSystemTools::Error(
- "CMAKE_AR was not found, please set to archive program. ",
- mf->GetDefinition("CMAKE_AR"));
+ "CMAKE_AR was not found, please set to archive program. " +
+ mf->GetSafeDefinition("CMAKE_AR"));
}
}
diff --git a/Source/cmGlobalMSYSMakefileGenerator.h b/Source/cmGlobalMSYSMakefileGenerator.h
index 23dbc5e31..d6e4847fe 100644
--- a/Source/cmGlobalMSYSMakefileGenerator.h
+++ b/Source/cmGlobalMSYSMakefileGenerator.h
@@ -19,7 +19,7 @@ public:
return new cmGlobalGeneratorSimpleFactory<cmGlobalMSYSMakefileGenerator>();
}
- ///! Get the name for the generator.
+ //! Get the name for the generator.
virtual std::string GetName() const
{
return cmGlobalMSYSMakefileGenerator::GetActualName();
diff --git a/Source/cmGlobalMinGWMakefileGenerator.cxx b/Source/cmGlobalMinGWMakefileGenerator.cxx
index c6d46e936..e218b4b95 100644
--- a/Source/cmGlobalMinGWMakefileGenerator.cxx
+++ b/Source/cmGlobalMinGWMakefileGenerator.cxx
@@ -23,7 +23,8 @@ void cmGlobalMinGWMakefileGenerator::EnableLanguage(
std::vector<std::string> const& l, cmMakefile* mf, bool optional)
{
this->FindMakeProgram(mf);
- std::string makeProgram = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
+ const std::string& makeProgram =
+ mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
std::vector<std::string> locations;
locations.push_back(cmSystemTools::GetProgramPath(makeProgram));
locations.push_back("/mingw/bin");
diff --git a/Source/cmGlobalMinGWMakefileGenerator.h b/Source/cmGlobalMinGWMakefileGenerator.h
index a994c9295..15297e3c7 100644
--- a/Source/cmGlobalMinGWMakefileGenerator.h
+++ b/Source/cmGlobalMinGWMakefileGenerator.h
@@ -19,7 +19,7 @@ public:
return new cmGlobalGeneratorSimpleFactory<
cmGlobalMinGWMakefileGenerator>();
}
- ///! Get the name for the generator.
+ //! Get the name for the generator.
virtual std::string GetName() const
{
return cmGlobalMinGWMakefileGenerator::GetActualName();
diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx
index ffe95f905..2273c00ac 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.cxx
+++ b/Source/cmGlobalNMakeMakefileGenerator.cxx
@@ -54,23 +54,23 @@ void cmGlobalNMakeMakefileGenerator::PrintCompilerAdvice(
this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
}
-void cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& projectDir,
- const std::string& targetName, const std::string& config, bool fast,
- int /*jobs*/, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int /*jobs*/, bool verbose,
+ std::vector<std::string> const& makeOptions)
{
std::vector<std::string> nmakeMakeOptions;
// Since we have full control over the invocation of nmake, let us
// make it quiet.
nmakeMakeOptions.push_back(this->MakeSilentFlag);
- nmakeMakeOptions.insert(nmakeMakeOptions.end(), makeOptions.begin(),
- makeOptions.end());
+ cmAppend(nmakeMakeOptions, makeOptions);
- this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
- makeCommand, makeProgram, projectName, projectDir, targetName, config,
- fast, cmake::NO_BUILD_PARALLEL_LEVEL, verbose, nmakeMakeOptions);
+ return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast,
+ cmake::NO_BUILD_PARALLEL_LEVEL, verbose, nmakeMakeOptions);
}
void cmGlobalNMakeMakefileGenerator::PrintBuildCommandAdvice(std::ostream& os,
diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h
index 06c48e22b..2fdf1ce5d 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.h
+++ b/Source/cmGlobalNMakeMakefileGenerator.h
@@ -21,7 +21,7 @@ public:
return new cmGlobalGeneratorSimpleFactory<
cmGlobalNMakeMakefileGenerator>();
}
- ///! Get the name for the generator.
+ //! Get the name for the generator.
std::string GetName() const override
{
return cmGlobalNMakeMakefileGenerator::GetActualName();
@@ -45,15 +45,12 @@ public:
bool optional) override;
protected:
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 920f6393c..2d52356bc 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -26,6 +26,7 @@
#include "cmMessageType.h"
#include "cmNinjaLinkLineComputer.h"
#include "cmOutputConverter.h"
+#include "cmRange.h"
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
@@ -126,164 +127,163 @@ std::string cmGlobalNinjaGenerator::EncodePath(const std::string& path)
return result;
}
-void cmGlobalNinjaGenerator::WriteBuild(
- std::ostream& os, const std::string& comment, const std::string& rule,
- const cmNinjaDeps& outputs, const cmNinjaDeps& implicitOuts,
- const cmNinjaDeps& explicitDeps, const cmNinjaDeps& implicitDeps,
- const cmNinjaDeps& orderOnlyDeps, const cmNinjaVars& variables,
- const std::string& rspfile, int cmdLineLimit, bool* usedResponseFile)
+void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
+ cmNinjaBuild const& build,
+ int cmdLineLimit,
+ bool* usedResponseFile)
{
// Make sure there is a rule.
- if (rule.empty()) {
- cmSystemTools::Error("No rule for WriteBuildStatement! called "
- "with comment: ",
- comment.c_str());
+ if (build.Rule.empty()) {
+ cmSystemTools::Error("No rule for WriteBuild! called with comment: " +
+ build.Comment);
return;
}
// Make sure there is at least one output file.
- if (outputs.empty()) {
- cmSystemTools::Error("No output files for WriteBuildStatement! called "
- "with comment: ",
- comment.c_str());
+ if (build.Outputs.empty()) {
+ cmSystemTools::Error(
+ "No output files for WriteBuild! called with comment: " + build.Comment);
return;
}
- cmGlobalNinjaGenerator::WriteComment(os, comment);
-
- std::string arguments;
-
- // TODO: Better formatting for when there are multiple input/output files.
+ cmGlobalNinjaGenerator::WriteComment(os, build.Comment);
- // Write explicit dependencies.
- for (std::string const& explicitDep : explicitDeps) {
- arguments += " " + EncodePath(explicitDep);
- }
-
- // Write implicit dependencies.
- if (!implicitDeps.empty()) {
- arguments += " |";
- for (std::string const& implicitDep : implicitDeps) {
- arguments += " " + EncodePath(implicitDep);
+ // Write output files.
+ std::string buildStr("build");
+ {
+ // Write explicit outputs
+ for (std::string const& output : build.Outputs) {
+ buildStr += " " + EncodePath(output);
+ if (this->ComputingUnknownDependencies) {
+ this->CombinedBuildOutputs.insert(output);
+ }
}
- }
-
- // Write order-only dependencies.
- if (!orderOnlyDeps.empty()) {
- arguments += " ||";
- for (std::string const& orderOnlyDep : orderOnlyDeps) {
- arguments += " " + EncodePath(orderOnlyDep);
+ // Write implicit outputs
+ if (!build.ImplicitOuts.empty()) {
+ buildStr += " |";
+ for (std::string const& implicitOut : build.ImplicitOuts) {
+ buildStr += " " + EncodePath(implicitOut);
+ }
}
+ buildStr += ":";
+
+ // Write the rule.
+ buildStr += " ";
+ buildStr += build.Rule;
}
- arguments += "\n";
+ std::string arguments;
+ {
+ // TODO: Better formatting for when there are multiple input/output files.
- std::string build;
+ // Write explicit dependencies.
+ for (std::string const& explicitDep : build.ExplicitDeps) {
+ arguments += " " + EncodePath(explicitDep);
+ }
- // Write outputs files.
- build += "build";
- for (std::string const& output : outputs) {
- build += " " + EncodePath(output);
- if (this->ComputingUnknownDependencies) {
- this->CombinedBuildOutputs.insert(output);
+ // Write implicit dependencies.
+ if (!build.ImplicitDeps.empty()) {
+ arguments += " |";
+ for (std::string const& implicitDep : build.ImplicitDeps) {
+ arguments += " " + EncodePath(implicitDep);
+ }
}
- }
- if (!implicitOuts.empty()) {
- build += " |";
- for (std::string const& implicitOut : implicitOuts) {
- build += " " + EncodePath(implicitOut);
+
+ // Write order-only dependencies.
+ if (!build.OrderOnlyDeps.empty()) {
+ arguments += " ||";
+ for (std::string const& orderOnlyDep : build.OrderOnlyDeps) {
+ arguments += " " + EncodePath(orderOnlyDep);
+ }
}
- }
- build += ":";
- // Write the rule.
- build += " " + rule;
+ arguments += "\n";
+ }
// Write the variables bound to this build statement.
- std::ostringstream variable_assignments;
- for (auto const& variable : variables) {
- cmGlobalNinjaGenerator::WriteVariable(variable_assignments, variable.first,
- variable.second, "", 1);
- }
+ std::string assignments;
+ {
+ std::ostringstream variable_assignments;
+ for (auto const& variable : build.Variables) {
+ cmGlobalNinjaGenerator::WriteVariable(
+ variable_assignments, variable.first, variable.second, "", 1);
+ }
- // check if a response file rule should be used
- std::string buildstr = build;
- std::string assignments = variable_assignments.str();
- bool useResponseFile = false;
- if (cmdLineLimit < 0 ||
- (cmdLineLimit > 0 &&
- (arguments.size() + buildstr.size() + assignments.size() + 1000) >
- static_cast<size_t>(cmdLineLimit))) {
- variable_assignments.str(std::string());
- cmGlobalNinjaGenerator::WriteVariable(variable_assignments, "RSP_FILE",
- rspfile, "", 1);
- assignments += variable_assignments.str();
- useResponseFile = true;
- }
- if (usedResponseFile) {
- *usedResponseFile = useResponseFile;
+ // check if a response file rule should be used
+ assignments = variable_assignments.str();
+ bool useResponseFile = false;
+ if (cmdLineLimit < 0 ||
+ (cmdLineLimit > 0 &&
+ (arguments.size() + buildStr.size() + assignments.size() + 1000) >
+ static_cast<size_t>(cmdLineLimit))) {
+ variable_assignments.str(std::string());
+ cmGlobalNinjaGenerator::WriteVariable(variable_assignments, "RSP_FILE",
+ build.RspFile, "", 1);
+ assignments += variable_assignments.str();
+ useResponseFile = true;
+ }
+ if (usedResponseFile) {
+ *usedResponseFile = useResponseFile;
+ }
}
- os << buildstr << arguments << assignments;
-}
-
-void cmGlobalNinjaGenerator::WritePhonyBuild(
- std::ostream& os, const std::string& comment, const cmNinjaDeps& outputs,
- const cmNinjaDeps& explicitDeps, const cmNinjaDeps& implicitDeps,
- const cmNinjaDeps& orderOnlyDeps, const cmNinjaVars& variables)
-{
- this->WriteBuild(os, comment, "phony", outputs,
- /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps,
- orderOnlyDeps, variables);
+ os << buildStr << arguments << assignments << "\n";
}
void cmGlobalNinjaGenerator::AddCustomCommandRule()
{
- this->AddRule("CUSTOM_COMMAND", "$COMMAND", "$DESC",
- "Rule for running custom commands.",
- /*depfile*/ "",
- /*deptype*/ "",
- /*rspfile*/ "",
- /*rspcontent*/ "",
- /*restat*/ "", // bound on each build statement as needed
- /*generator*/ false);
+ cmNinjaRule rule("CUSTOM_COMMAND");
+ rule.Command = "$COMMAND";
+ rule.Description = "$DESC";
+ rule.Comment = "Rule for running custom commands.";
+ this->AddRule(rule);
}
void cmGlobalNinjaGenerator::WriteCustomCommandBuild(
const std::string& command, const std::string& description,
- const std::string& comment, const std::string& depfile, bool uses_terminal,
- bool restat, const cmNinjaDeps& outputs, const cmNinjaDeps& deps,
- const cmNinjaDeps& orderOnly)
+ const std::string& comment, const std::string& depfile,
+ const std::string& job_pool, bool uses_terminal, bool restat,
+ const cmNinjaDeps& outputs, const cmNinjaDeps& explicitDeps,
+ const cmNinjaDeps& orderOnlyDeps)
{
- std::string cmd = command; // NOLINT(*)
-#ifdef _WIN32
- if (cmd.empty())
- // TODO Shouldn't an empty command be handled by ninja?
- cmd = "cmd.exe /c";
-#endif
-
this->AddCustomCommandRule();
- cmNinjaVars vars;
- vars["COMMAND"] = cmd;
- vars["DESC"] = EncodeLiteral(description);
- if (restat) {
- vars["restat"] = "1";
- }
- if (uses_terminal && SupportsConsolePool()) {
- vars["pool"] = "console";
- }
- if (!depfile.empty()) {
- vars["depfile"] = depfile;
+ {
+ cmNinjaBuild build("CUSTOM_COMMAND");
+ build.Comment = comment;
+ build.Outputs = outputs;
+ build.ExplicitDeps = explicitDeps;
+ build.OrderOnlyDeps = orderOnlyDeps;
+
+ cmNinjaVars& vars = build.Variables;
+ {
+ std::string cmd = command; // NOLINT(*)
+#ifdef _WIN32
+ if (cmd.empty())
+ // TODO Shouldn't an empty command be handled by ninja?
+ cmd = "cmd.exe /c";
+#endif
+ vars["COMMAND"] = std::move(cmd);
+ }
+ vars["DESC"] = EncodeLiteral(description);
+ if (restat) {
+ vars["restat"] = "1";
+ }
+ if (uses_terminal && SupportsConsolePool()) {
+ vars["pool"] = "console";
+ } else if (!job_pool.empty()) {
+ vars["pool"] = job_pool;
+ }
+ if (!depfile.empty()) {
+ vars["depfile"] = depfile;
+ }
+ this->WriteBuild(*this->BuildFileStream, build);
}
- this->WriteBuild(*this->BuildFileStream, comment, "CUSTOM_COMMAND", outputs,
- /*implicitOuts=*/cmNinjaDeps(), deps, cmNinjaDeps(),
- orderOnly, vars);
if (this->ComputingUnknownDependencies) {
// we need to track every dependency that comes in, since we are trying
// to find dependencies that are side effects of build commands
- for (std::string const& dep : deps) {
+ for (std::string const& dep : explicitDeps) {
this->CombinedCustomCommandExplicitDependencies.insert(dep);
}
}
@@ -291,111 +291,79 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild(
void cmGlobalNinjaGenerator::AddMacOSXContentRule()
{
- cmLocalGenerator* lg = this->LocalGenerators[0];
-
- std::ostringstream cmd;
- cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
- cmOutputConverter::SHELL)
- << " -E copy $in $out";
-
- this->AddRule("COPY_OSX_CONTENT", cmd.str(), "Copying OS X Content $out",
- "Rule for copying OS X bundle content file.",
- /*depfile*/ "",
- /*deptype*/ "",
- /*rspfile*/ "",
- /*rspcontent*/ "",
- /*restat*/ "",
- /*generator*/ false);
+ cmNinjaRule rule("COPY_OSX_CONTENT");
+ rule.Command = CMakeCmd() + " -E copy $in $out";
+ rule.Description = "Copying OS X Content $out";
+ rule.Comment = "Rule for copying OS X bundle content file.";
+ this->AddRule(rule);
}
-void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(const std::string& input,
- const std::string& output)
+void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(std::string input,
+ std::string output)
{
this->AddMacOSXContentRule();
-
- cmNinjaDeps outputs;
- outputs.push_back(output);
- cmNinjaDeps deps;
- deps.push_back(input);
- cmNinjaVars vars;
-
- this->WriteBuild(*this->BuildFileStream, "", "COPY_OSX_CONTENT", outputs,
- /*implicitOuts=*/cmNinjaDeps(), deps, cmNinjaDeps(),
- cmNinjaDeps(), cmNinjaVars());
+ {
+ cmNinjaBuild build("COPY_OSX_CONTENT");
+ build.Outputs.push_back(std::move(output));
+ build.ExplicitDeps.push_back(std::move(input));
+ this->WriteBuild(*this->BuildFileStream, build);
+ }
}
-void cmGlobalNinjaGenerator::WriteRule(
- std::ostream& os, const std::string& name, const std::string& command,
- const std::string& description, const std::string& comment,
- const std::string& depfile, const std::string& deptype,
- const std::string& rspfile, const std::string& rspcontent,
- const std::string& restat, bool generator)
+void cmGlobalNinjaGenerator::WriteRule(std::ostream& os,
+ cmNinjaRule const& rule)
{
+ // -- Parameter checks
// Make sure the rule has a name.
- if (name.empty()) {
- cmSystemTools::Error("No name given for WriteRuleStatement! called "
- "with comment: ",
- comment.c_str());
+ if (rule.Name.empty()) {
+ cmSystemTools::Error("No name given for WriteRule! called with comment: " +
+ rule.Comment);
return;
}
// Make sure a command is given.
- if (command.empty()) {
- cmSystemTools::Error("No command given for WriteRuleStatement! called "
- "with comment: ",
- comment.c_str());
+ if (rule.Command.empty()) {
+ cmSystemTools::Error(
+ "No command given for WriteRule! called with comment: " + rule.Comment);
return;
}
- cmGlobalNinjaGenerator::WriteComment(os, comment);
-
- // Write the rule.
- os << "rule " << name << "\n";
-
- // Write the depfile if any.
- if (!depfile.empty()) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "depfile = " << depfile << "\n";
- }
-
- // Write the deptype if any.
- if (!deptype.empty()) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "deps = " << deptype << "\n";
+ // Make sure response file content is given
+ if (!rule.RspFile.empty() && rule.RspContent.empty()) {
+ cmSystemTools::Error("rspfile but no rspfile_content given for WriteRule! "
+ "called with comment: " +
+ rule.Comment);
+ return;
}
- // Write the command.
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "command = " << command << "\n";
+ // -- Write rule
+ // Write rule intro
+ cmGlobalNinjaGenerator::WriteComment(os, rule.Comment);
+ os << "rule " << rule.Name << '\n';
- // Write the description if any.
- if (!description.empty()) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "description = " << description << "\n";
- }
-
- if (!rspfile.empty()) {
- if (rspcontent.empty()) {
- cmSystemTools::Error("No rspfile_content given!", comment.c_str());
- return;
+ // Write rule key/value pairs
+ auto writeKV = [&os](const char* key, std::string const& value) {
+ if (!value.empty()) {
+ cmGlobalNinjaGenerator::Indent(os, 1);
+ os << key << " = " << value << '\n';
}
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "rspfile = " << rspfile << "\n";
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "rspfile_content = " << rspcontent << "\n";
- }
+ };
- if (!restat.empty()) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "restat = " << restat << "\n";
+ writeKV("depfile", rule.DepFile);
+ writeKV("deps", rule.DepType);
+ writeKV("command", rule.Command);
+ writeKV("description", rule.Description);
+ if (!rule.RspFile.empty()) {
+ writeKV("rspfile", rule.RspFile);
+ writeKV("rspfile_content", rule.RspContent);
}
-
- if (generator) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "generator = 1\n";
+ writeKV("restat", rule.Restat);
+ if (rule.Generator) {
+ writeKV("generator", "1");
}
- os << "\n";
+ // Finish rule
+ os << '\n';
}
void cmGlobalNinjaGenerator::WriteVariable(std::ostream& os,
@@ -407,8 +375,8 @@ void cmGlobalNinjaGenerator::WriteVariable(std::ostream& os,
// Make sure we have a name.
if (name.empty()) {
cmSystemTools::Error("No name given for WriteVariable! called "
- "with comment: ",
- comment.c_str());
+ "with comment: " +
+ comment);
return;
}
@@ -445,9 +413,6 @@ void cmGlobalNinjaGenerator::WriteDefault(std::ostream& os,
cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm)
: cmGlobalCommonGenerator(cm)
- , BuildFileStream(nullptr)
- , RulesFileStream(nullptr)
- , CompileCommandsStream(nullptr)
, UsingGCCOnWindows(false)
, ComputingUnknownDependencies(false)
, PolicyCMP0058(cmPolicies::WARN)
@@ -508,8 +473,12 @@ void cmGlobalNinjaGenerator::Generate()
msg.str());
return;
}
- this->OpenBuildFileStream();
- this->OpenRulesFileStream();
+ if (!this->OpenBuildFileStream()) {
+ return;
+ }
+ if (!this->OpenRulesFileStream()) {
+ return;
+ }
this->TargetDependsClosures.clear();
@@ -591,7 +560,7 @@ void cmGlobalNinjaGenerator::CheckNinjaFeatures()
static std::string const k_DYNDEP_ = ".dyndep-";
std::string::size_type pos = this->NinjaVersion.find(k_DYNDEP_);
if (pos != std::string::npos) {
- const char* fv = this->NinjaVersion.c_str() + pos + k_DYNDEP_.size();
+ const char* fv = &this->NinjaVersion[pos + k_DYNDEP_.size()];
cmSystemTools::StringToULong(fv, &this->NinjaSupportsDyndeps);
}
}
@@ -656,13 +625,20 @@ void cmGlobalNinjaGenerator::EnableLanguage(
this->ResolveLanguageCompiler(l, mf, optional);
}
#ifdef _WIN32
- if ((mf->GetSafeDefinition("CMAKE_C_SIMULATE_ID") != "MSVC") &&
- (mf->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID") != "MSVC") &&
- (mf->IsOn("CMAKE_COMPILER_IS_MINGW") ||
- (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "GNU") ||
- (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "GNU") ||
- (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "Clang") ||
- (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "Clang"))) {
+ const bool clangGnuMode =
+ ((mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "Clang") &&
+ (mf->GetSafeDefinition("CMAKE_C_COMPILER_FRONTEND_VARIANT") == "GNU")) ||
+ ((mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "Clang") &&
+ (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_FRONTEND_VARIANT") == "GNU"));
+
+ if (clangGnuMode ||
+ ((mf->GetSafeDefinition("CMAKE_C_SIMULATE_ID") != "MSVC") &&
+ (mf->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID") != "MSVC") &&
+ (mf->IsOn("CMAKE_COMPILER_IS_MINGW") ||
+ (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "GNU") ||
+ (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "GNU") ||
+ (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "Clang") ||
+ (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "Clang")))) {
this->UsingGCCOnWindows = true;
}
#endif
@@ -676,59 +652,52 @@ void cmGlobalNinjaGenerator::EnableLanguage(
// cmGlobalXCodeGenerator
// Called by:
// cmGlobalGenerator::Build()
-void cmGlobalNinjaGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& /*projectName*/, const std::string& /*projectDir*/,
- const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
- int jobs, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalNinjaGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& /*projectName*/,
+ const std::string& /*projectDir*/,
+ std::vector<std::string> const& targetNames, const std::string& /*config*/,
+ bool /*fast*/, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions)
{
- makeCommand.add(this->SelectMakeProgram(makeProgram));
+ GeneratedMakeCommand makeCommand;
+ makeCommand.Add(this->SelectMakeProgram(makeProgram));
if (verbose) {
- makeCommand.add("-v");
+ makeCommand.Add("-v");
}
if ((jobs != cmake::NO_BUILD_PARALLEL_LEVEL) &&
(jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL)) {
- makeCommand.add("-j", std::to_string(jobs));
+ makeCommand.Add("-j", std::to_string(jobs));
}
- makeCommand.add(makeOptions.begin(), makeOptions.end());
- if (!targetName.empty()) {
- if (targetName == "clean") {
- makeCommand.add("-t", "clean");
- } else {
- makeCommand.add(targetName);
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ for (const auto& tname : targetNames) {
+ if (!tname.empty()) {
+ makeCommand.Add(tname);
}
}
+ return { std::move(makeCommand) };
}
// Non-virtual public methods.
-void cmGlobalNinjaGenerator::AddRule(
- const std::string& name, const std::string& command,
- const std::string& description, const std::string& comment,
- const std::string& depfile, const std::string& deptype,
- const std::string& rspfile, const std::string& rspcontent,
- const std::string& restat, bool generator)
+void cmGlobalNinjaGenerator::AddRule(cmNinjaRule const& rule)
{
// Do not add the same rule twice.
- if (this->HasRule(name)) {
+ if (!this->Rules.insert(rule.Name).second) {
return;
}
-
- this->Rules.insert(name);
- cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream, name, command,
- description, comment, depfile, deptype,
- rspfile, rspcontent, restat, generator);
-
- this->RuleCmdLength[name] = static_cast<int>(command.size());
+ // Store command length
+ this->RuleCmdLength[rule.Name] = static_cast<int>(rule.Command.size());
+ // Write rule
+ cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream, rule);
}
bool cmGlobalNinjaGenerator::HasRule(const std::string& name)
{
- RulesSetType::const_iterator rule = this->Rules.find(name);
- return (rule != this->Rules.end());
+ return (this->Rules.find(name) != this->Rules.end());
}
// Private virtual overrides
@@ -754,7 +723,7 @@ void cmGlobalNinjaGenerator::ComputeTargetObjectDirectory(
// Private methods
-void cmGlobalNinjaGenerator::OpenBuildFileStream()
+bool cmGlobalNinjaGenerator::OpenBuildFileStream()
{
// Compute Ninja's build file path.
std::string buildFilePath =
@@ -764,12 +733,12 @@ void cmGlobalNinjaGenerator::OpenBuildFileStream()
// Get a stream where to generate things.
if (!this->BuildFileStream) {
- this->BuildFileStream = new cmGeneratedFileStream(
+ this->BuildFileStream = cm::make_unique<cmGeneratedFileStream>(
buildFilePath, false, this->GetMakefileEncoding());
- if (!this->BuildFileStream) {
+ if (!(*this->BuildFileStream)) {
// An error message is generated by the constructor if it cannot
// open the file.
- return;
+ return false;
}
}
@@ -780,19 +749,20 @@ void cmGlobalNinjaGenerator::OpenBuildFileStream()
*this->BuildFileStream
<< "# This file contains all the build statements describing the\n"
<< "# compilation DAG.\n\n";
+
+ return true;
}
void cmGlobalNinjaGenerator::CloseBuildFileStream()
{
if (this->BuildFileStream) {
- delete this->BuildFileStream;
- this->BuildFileStream = nullptr;
+ this->BuildFileStream.reset();
} else {
cmSystemTools::Error("Build file stream was not open.");
}
}
-void cmGlobalNinjaGenerator::OpenRulesFileStream()
+bool cmGlobalNinjaGenerator::OpenRulesFileStream()
{
// Compute Ninja's build file path.
std::string rulesFilePath =
@@ -802,12 +772,12 @@ void cmGlobalNinjaGenerator::OpenRulesFileStream()
// Get a stream where to generate things.
if (!this->RulesFileStream) {
- this->RulesFileStream = new cmGeneratedFileStream(
+ this->RulesFileStream = cm::make_unique<cmGeneratedFileStream>(
rulesFilePath, false, this->GetMakefileEncoding());
- if (!this->RulesFileStream) {
+ if (!(*this->RulesFileStream)) {
// An error message is generated by the constructor if it cannot
// open the file.
- return;
+ return false;
}
}
@@ -822,13 +792,13 @@ void cmGlobalNinjaGenerator::OpenRulesFileStream()
<< "# It is included in the main '" << NINJA_BUILD_FILE << "'.\n\n"
;
/* clang-format on */
+ return true;
}
void cmGlobalNinjaGenerator::CloseRulesFileStream()
{
if (this->RulesFileStream) {
- delete this->RulesFileStream;
- this->RulesFileStream = nullptr;
+ this->RulesFileStream.reset();
} else {
cmSystemTools::Error("Rules file stream was not open.");
}
@@ -871,6 +841,11 @@ std::string const& cmGlobalNinjaGenerator::ConvertToNinjaPath(
.first->second;
}
+void cmGlobalNinjaGenerator::AddAdditionalCleanFile(std::string fileName)
+{
+ this->AdditionalCleanFiles.emplace(std::move(fileName));
+}
+
void cmGlobalNinjaGenerator::AddCXXCompileCommand(
const std::string& commandLine, const std::string& sourceFile)
{
@@ -885,7 +860,8 @@ void cmGlobalNinjaGenerator::AddCXXCompileCommand(
}
// Get a stream where to generate things.
- this->CompileCommandsStream = new cmGeneratedFileStream(buildFilePath);
+ this->CompileCommandsStream =
+ cm::make_unique<cmGeneratedFileStream>(buildFilePath);
*this->CompileCommandsStream << "[";
} else {
*this->CompileCommandsStream << "," << std::endl;
@@ -899,11 +875,11 @@ void cmGlobalNinjaGenerator::AddCXXCompileCommand(
/* clang-format off */
*this->CompileCommandsStream << "\n{\n"
- << " \"directory\": \""
+ << R"( "directory": ")"
<< cmGlobalGenerator::EscapeJSON(buildFileDir) << "\",\n"
- << " \"command\": \""
+ << R"( "command": ")"
<< cmGlobalGenerator::EscapeJSON(commandLine) << "\",\n"
- << " \"file\": \""
+ << R"( "file": ")"
<< cmGlobalGenerator::EscapeJSON(sourceFileName) << "\"\n"
<< "}";
/* clang-format on */
@@ -913,8 +889,7 @@ void cmGlobalNinjaGenerator::CloseCompileCommandsStream()
{
if (this->CompileCommandsStream) {
*this->CompileCommandsStream << "\n]";
- delete this->CompileCommandsStream;
- this->CompileCommandsStream = nullptr;
+ this->CompileCommandsStream.reset();
}
}
@@ -944,7 +919,8 @@ void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies()
std::back_inserter(orderOnlyDeps));
WriteCustomCommandBuild(/*command=*/"", /*description=*/"",
"Assume dependencies for generated source file.",
- /*depfile*/ "", /*uses_terminal*/ false,
+ /*depfile*/ "", /*job_pool*/ "",
+ /*uses_terminal*/ false,
/*restat*/ true, cmNinjaDeps(1, asd.first),
cmNinjaDeps(), orderOnlyDeps);
}
@@ -1010,8 +986,7 @@ void cmGlobalNinjaGenerator::AppendTargetDepends(
{
if (target->GetType() == cmStateEnums::GLOBAL_TARGET) {
// These depend only on other CMake-provided targets, e.g. "all".
- std::set<BT<std::string>> const& utils = target->GetUtilities();
- for (BT<std::string> const& util : utils) {
+ for (BT<std::string> const& util : target->GetUtilities()) {
std::string d =
target->GetLocalGenerator()->GetCurrentBinaryDirectory() + "/" +
util.Value;
@@ -1019,15 +994,15 @@ void cmGlobalNinjaGenerator::AppendTargetDepends(
}
} else {
cmNinjaDeps outs;
- cmTargetDependSet const& targetDeps = this->GetTargetDirectDepends(target);
- for (cmTargetDepend const& targetDep : targetDeps) {
+ for (cmTargetDepend const& targetDep :
+ this->GetTargetDirectDepends(target)) {
if (targetDep->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
this->AppendTargetOutputs(targetDep, outs, depends);
}
std::sort(outs.begin(), outs.end());
- outputs.insert(outputs.end(), outs.begin(), outs.end());
+ cmAppend(outputs, outs);
}
}
@@ -1036,8 +1011,7 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
{
cmNinjaOuts outs;
this->AppendTargetDependsClosure(target, outs, true);
-
- outputs.insert(outputs.end(), outs.begin(), outs.end());
+ cmAppend(outputs, outs);
}
void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
@@ -1054,10 +1028,9 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
// relevant for filling the cache entries properly isolated and a global
// result set that is relevant for the result of the top level call to
// AppendTargetDependsClosure.
- auto const& targetDeps = this->GetTargetDirectDepends(target);
cmNinjaOuts this_outs; // this will be the new cache entry
- for (auto const& dep_target : targetDeps) {
+ for (auto const& dep_target : this->GetTargetDirectDepends(target)) {
if (dep_target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
@@ -1107,6 +1080,8 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os)
cmGlobalNinjaGenerator::WriteDivider(os);
os << "# Target aliases.\n\n";
+ cmNinjaBuild build("phony");
+ build.Outputs.emplace_back("");
for (auto const& ta : TargetAliases) {
// Don't write ambiguous aliases.
if (!ta.second) {
@@ -1119,10 +1094,13 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os)
continue;
}
- cmNinjaDeps deps;
- this->AppendTargetOutputs(ta.second, deps);
-
- this->WritePhonyBuild(os, "", cmNinjaDeps(1, ta.first), deps);
+ // Outputs
+ build.Outputs[0] = ta.first;
+ // Explicit depdendencies
+ build.ExplicitDeps.clear();
+ this->AppendTargetOutputs(ta.second, build.ExplicitDeps);
+ // Write
+ this->WriteBuild(os, build);
}
}
@@ -1131,13 +1109,22 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
cmGlobalNinjaGenerator::WriteDivider(os);
os << "# Folder targets.\n\n";
+ std::string const& rootBinaryDir =
+ this->LocalGenerators[0]->GetBinaryDirectory();
+
std::map<std::string, cmNinjaDeps> targetsPerFolder;
for (cmLocalGenerator const* lg : this->LocalGenerators) {
- const std::string currentBinaryFolder(
+ std::string const& currentBinaryFolder(
lg->GetStateSnapshot().GetDirectory().GetCurrentBinary());
+
+ // Do not generate a rule for the root binary dir.
+ if (currentBinaryFolder == rootBinaryDir) {
+ continue;
+ }
+
// The directory-level rule should depend on the target-level rules
// for all targets in the directory.
- targetsPerFolder[currentBinaryFolder] = cmNinjaDeps();
+ cmNinjaDeps& folderTargets = targetsPerFolder[currentBinaryFolder];
for (auto gt : lg->GetGeneratorTargets()) {
cmStateEnums::TargetType const type = gt->GetType();
if ((type == cmStateEnums::EXECUTABLE ||
@@ -1147,39 +1134,34 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
type == cmStateEnums::OBJECT_LIBRARY ||
type == cmStateEnums::UTILITY) &&
!gt->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
- targetsPerFolder[currentBinaryFolder].push_back(gt->GetName());
+ folderTargets.push_back(gt->GetName());
}
}
// The directory-level rule should depend on the directory-level
// rules of the subdirectories.
- std::vector<cmStateSnapshot> const& children =
- lg->GetStateSnapshot().GetChildren();
- for (cmStateSnapshot const& state : children) {
- std::string const currentBinaryDir =
+ for (cmStateSnapshot const& state : lg->GetStateSnapshot().GetChildren()) {
+ std::string const& currentBinaryDir =
state.GetDirectory().GetCurrentBinary();
-
- targetsPerFolder[currentBinaryFolder].push_back(
+ folderTargets.push_back(
this->ConvertToNinjaPath(currentBinaryDir + "/all"));
}
}
- std::string const rootBinaryDir =
- this->LocalGenerators[0]->GetBinaryDirectory();
- for (auto const& it : targetsPerFolder) {
- cmGlobalNinjaGenerator::WriteDivider(os);
- std::string const& currentBinaryDir = it.first;
+ if (!targetsPerFolder.empty()) {
+ cmNinjaBuild build("phony");
+ build.Outputs.emplace_back("");
+ for (auto& it : targetsPerFolder) {
+ cmGlobalNinjaGenerator::WriteDivider(os);
+ std::string const& currentBinaryDir = it.first;
- // Do not generate a rule for the root binary dir.
- if (rootBinaryDir.length() >= currentBinaryDir.length()) {
- continue;
+ // Setup target
+ build.Comment = "Folder: " + currentBinaryDir;
+ build.Outputs[0] = this->ConvertToNinjaPath(currentBinaryDir + "/all");
+ build.ExplicitDeps = std::move(it.second);
+ // Write target
+ this->WriteBuild(os, build);
}
-
- std::string const comment = "Folder: " + currentBinaryDir;
- cmNinjaDeps output(1);
- output.push_back(this->ConvertToNinjaPath(currentBinaryDir + "/all"));
-
- this->WritePhonyBuild(os, comment, output, it.second);
}
}
@@ -1216,26 +1198,21 @@ void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os)
for (cmLocalGenerator* lg : this->LocalGenerators) {
// get the vector of files created by this makefile and convert them
// to ninja paths, which are all relative in respect to the build directory
- const std::vector<std::string>& files =
- lg->GetMakefile()->GetOutputFiles();
- for (std::string const& file : files) {
+ for (std::string const& file : lg->GetMakefile()->GetOutputFiles()) {
knownDependencies.insert(this->ConvertToNinjaPath(file));
}
if (!this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
// get list files which are implicit dependencies as well and will be
// phony for rebuild manifest
- std::vector<std::string> const& lf = lg->GetMakefile()->GetListFiles();
- for (std::string const& j : lf) {
+ for (std::string const& j : lg->GetMakefile()->GetListFiles()) {
knownDependencies.insert(this->ConvertToNinjaPath(j));
}
}
- std::vector<cmGeneratorExpressionEvaluationFile*> const& ef =
- lg->GetMakefile()->GetEvaluationFiles();
- for (cmGeneratorExpressionEvaluationFile* li : ef) {
+ for (cmGeneratorExpressionEvaluationFile* li :
+ lg->GetMakefile()->GetEvaluationFiles()) {
// get all the files created by generator expressions and convert them
// to ninja paths
- std::vector<std::string> evaluationFiles = li->GetFiles();
- for (std::string const& evaluationFile : evaluationFiles) {
+ for (std::string const& evaluationFile : li->GetFiles()) {
knownDependencies.insert(this->ConvertToNinjaPath(evaluationFile));
}
}
@@ -1265,23 +1242,26 @@ void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os)
knownDependencies.begin(), knownDependencies.end(),
std::back_inserter(unknownExplicitDepends));
- std::string const rootBuildDirectory =
- this->GetCMakeInstance()->GetHomeOutputDirectory();
- bool const inSourceBuild =
- (rootBuildDirectory == this->GetCMakeInstance()->GetHomeDirectory());
std::vector<std::string> warnExplicitDepends;
- for (std::string const& i : unknownExplicitDepends) {
- // verify the file is in the build directory
- std::string const absDepPath =
- cmSystemTools::CollapseFullPath(i, rootBuildDirectory.c_str());
- bool const inBuildDir =
- cmSystemTools::IsSubDirectory(absDepPath, rootBuildDirectory);
- if (inBuildDir) {
- cmNinjaDeps deps(1, i);
- this->WritePhonyBuild(os, "", deps, cmNinjaDeps());
- if (this->PolicyCMP0058 == cmPolicies::WARN && !inSourceBuild &&
- warnExplicitDepends.size() < 10) {
- warnExplicitDepends.push_back(i);
+ if (!unknownExplicitDepends.empty()) {
+ cmake* cmk = this->GetCMakeInstance();
+ std::string const& buildRoot = cmk->GetHomeOutputDirectory();
+ bool const inSource = (buildRoot == cmk->GetHomeDirectory());
+ bool const warn = (!inSource && (this->PolicyCMP0058 == cmPolicies::WARN));
+ cmNinjaBuild build("phony");
+ build.Outputs.emplace_back("");
+ for (std::string const& ued : unknownExplicitDepends) {
+ // verify the file is in the build directory
+ std::string const absDepPath =
+ cmSystemTools::CollapseFullPath(ued, buildRoot);
+ if (cmSystemTools::IsSubDirectory(absDepPath, buildRoot)) {
+ // Generate phony build statement
+ build.Outputs[0] = ued;
+ this->WriteBuild(os, build);
+ // Add to warning on demand
+ if (warn && warnExplicitDepends.size() < 10) {
+ warnExplicitDepends.push_back(ued);
+ }
}
}
}
@@ -1322,14 +1302,14 @@ void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os)
void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os)
{
- cmNinjaDeps outputs;
- outputs.push_back(this->TargetAll);
-
- this->WritePhonyBuild(os, "The main all target.", outputs,
- this->AllDependencies);
+ cmNinjaBuild build("phony");
+ build.Comment = "The main all target.";
+ build.Outputs.push_back(this->TargetAll);
+ build.ExplicitDeps = this->AllDependencies;
+ this->WriteBuild(os, build);
if (!this->HasOutputPathPrefix()) {
- cmGlobalNinjaGenerator::WriteDefault(os, outputs,
+ cmGlobalNinjaGenerator::WriteDefault(os, build.Outputs,
"Make the all target the default.");
}
}
@@ -1341,84 +1321,74 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
}
cmLocalGenerator* lg = this->LocalGenerators[0];
- std::ostringstream cmd;
- cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
- cmOutputConverter::SHELL)
- << " -S"
- << lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
- cmOutputConverter::SHELL)
- << " -B"
- << lg->ConvertToOutputFormat(lg->GetBinaryDirectory(),
- cmOutputConverter::SHELL);
- WriteRule(*this->RulesFileStream, "RERUN_CMAKE", cmd.str(),
- "Re-running CMake...", "Rule for re-running cmake.",
- /*depfile=*/"",
- /*deptype=*/"",
- /*rspfile=*/"",
- /*rspcontent*/ "",
- /*restat=*/"",
- /*generator=*/true);
-
- cmNinjaDeps implicitDeps;
- cmNinjaDeps explicitDeps;
+ {
+ cmNinjaRule rule("RERUN_CMAKE");
+ rule.Command = CMakeCmd();
+ rule.Command += " -S";
+ rule.Command += lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
+ cmOutputConverter::SHELL);
+ rule.Command += " -B";
+ rule.Command += lg->ConvertToOutputFormat(lg->GetBinaryDirectory(),
+ cmOutputConverter::SHELL);
+ rule.Description = "Re-running CMake...";
+ rule.Comment = "Rule for re-running cmake.";
+ rule.Generator = true;
+ WriteRule(*this->RulesFileStream, rule);
+ }
+
+ cmNinjaBuild reBuild("RERUN_CMAKE");
+ reBuild.Comment = "Re-run CMake if any of its inputs changed.";
+ reBuild.Outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE));
+
for (cmLocalGenerator* localGen : this->LocalGenerators) {
- std::vector<std::string> const& lf =
- localGen->GetMakefile()->GetListFiles();
- for (std::string const& fi : lf) {
- implicitDeps.push_back(this->ConvertToNinjaPath(fi));
+ for (std::string const& fi : localGen->GetMakefile()->GetListFiles()) {
+ reBuild.ImplicitDeps.push_back(this->ConvertToNinjaPath(fi));
}
}
- implicitDeps.push_back(this->CMakeCacheFile);
+ reBuild.ImplicitDeps.push_back(this->CMakeCacheFile);
- cmNinjaVars variables;
// Use 'console' pool to get non buffered output of the CMake re-run call
// Available since Ninja 1.5
if (SupportsConsolePool()) {
- variables["pool"] = "console";
+ reBuild.Variables["pool"] = "console";
}
cmake* cm = this->GetCMakeInstance();
if (this->SupportsManifestRestat() && cm->DoWriteGlobVerifyTarget()) {
- std::ostringstream verify_cmd;
- verify_cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
- cmOutputConverter::SHELL)
- << " -P "
- << lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
- cmOutputConverter::SHELL);
-
- WriteRule(*this->RulesFileStream, "VERIFY_GLOBS", verify_cmd.str(),
- "Re-checking globbed directories...",
- "Rule for re-checking globbed directories.",
- /*depfile=*/"",
- /*deptype=*/"",
- /*rspfile=*/"",
- /*rspcontent*/ "",
- /*restat=*/"",
- /*generator=*/true);
-
- std::string verifyForce = cm->GetGlobVerifyScript() + "_force";
- cmNinjaDeps verifyForceDeps(1, this->NinjaOutputPath(verifyForce));
-
- this->WritePhonyBuild(os, "Phony target to force glob verification run.",
- verifyForceDeps, cmNinjaDeps());
-
- variables["restat"] = "1";
+ {
+ cmNinjaRule rule("VERIFY_GLOBS");
+ rule.Command = CMakeCmd();
+ rule.Command += " -P ";
+ rule.Command += lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
+ cmOutputConverter::SHELL);
+ rule.Description = "Re-checking globbed directories...";
+ rule.Comment = "Rule for re-checking globbed directories.";
+ rule.Generator = true;
+ this->WriteRule(*this->RulesFileStream, rule);
+ }
+
+ cmNinjaBuild phonyBuild("phony");
+ phonyBuild.Comment = "Phony target to force glob verification run.";
+ phonyBuild.Outputs.push_back(cm->GetGlobVerifyScript() + "_force");
+ this->WriteBuild(os, phonyBuild);
+
+ reBuild.Variables["restat"] = "1";
std::string const verifyScriptFile =
this->NinjaOutputPath(cm->GetGlobVerifyScript());
std::string const verifyStampFile =
this->NinjaOutputPath(cm->GetGlobVerifyStamp());
- this->WriteBuild(os,
- "Re-run CMake to check if globbed directories changed.",
- "VERIFY_GLOBS",
- /*outputs=*/cmNinjaDeps(1, verifyStampFile),
- /*implicitOuts=*/cmNinjaDeps(),
- /*explicitDeps=*/cmNinjaDeps(),
- /*implicitDeps=*/verifyForceDeps,
- /*orderOnlyDeps=*/cmNinjaDeps(), variables);
-
- variables.erase("restat");
- implicitDeps.push_back(verifyScriptFile);
- explicitDeps.push_back(verifyStampFile);
+ {
+ cmNinjaBuild vgBuild("VERIFY_GLOBS");
+ vgBuild.Comment =
+ "Re-run CMake to check if globbed directories changed.";
+ vgBuild.Outputs.push_back(verifyStampFile);
+ vgBuild.ImplicitDeps = phonyBuild.Outputs;
+ vgBuild.Variables = reBuild.Variables;
+ this->WriteBuild(os, vgBuild);
+ }
+ reBuild.Variables.erase("restat");
+ reBuild.ImplicitDeps.push_back(verifyScriptFile);
+ reBuild.ExplicitDeps.push_back(verifyStampFile);
} else if (!this->SupportsManifestRestat() &&
cm->DoWriteGlobVerifyTarget()) {
std::ostringstream msg;
@@ -1436,31 +1406,36 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
msg.str());
}
- std::sort(implicitDeps.begin(), implicitDeps.end());
- implicitDeps.erase(std::unique(implicitDeps.begin(), implicitDeps.end()),
- implicitDeps.end());
+ std::sort(reBuild.ImplicitDeps.begin(), reBuild.ImplicitDeps.end());
+ reBuild.ImplicitDeps.erase(
+ std::unique(reBuild.ImplicitDeps.begin(), reBuild.ImplicitDeps.end()),
+ reBuild.ImplicitDeps.end());
- std::string const ninjaBuildFile = this->NinjaOutputPath(NINJA_BUILD_FILE);
- this->WriteBuild(os, "Re-run CMake if any of its inputs changed.",
- "RERUN_CMAKE",
- /*outputs=*/cmNinjaDeps(1, ninjaBuildFile),
- /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps,
- /*orderOnlyDeps=*/cmNinjaDeps(), variables);
+ this->WriteBuild(os, reBuild);
- cmNinjaDeps missingInputs;
- std::set_difference(std::make_move_iterator(implicitDeps.begin()),
- std::make_move_iterator(implicitDeps.end()),
- CustomCommandOutputs.begin(), CustomCommandOutputs.end(),
- std::back_inserter(missingInputs));
+ {
+ cmNinjaBuild build("phony");
+ build.Comment = "A missing CMake input file is not an error.";
+ std::set_difference(std::make_move_iterator(reBuild.ImplicitDeps.begin()),
+ std::make_move_iterator(reBuild.ImplicitDeps.end()),
+ CustomCommandOutputs.begin(),
+ CustomCommandOutputs.end(),
+ std::back_inserter(build.Outputs));
+ this->WriteBuild(os, build);
+ }
+}
- this->WritePhonyBuild(os, "A missing CMake input file is not an error.",
- missingInputs, cmNinjaDeps());
+std::string cmGlobalNinjaGenerator::CMakeCmd() const
+{
+ cmLocalGenerator* lgen = this->LocalGenerators.at(0);
+ return lgen->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
+ cmOutputConverter::SHELL);
}
-std::string cmGlobalNinjaGenerator::ninjaCmd() const
+std::string cmGlobalNinjaGenerator::NinjaCmd() const
{
cmLocalGenerator* lgen = this->LocalGenerators[0];
- if (lgen) {
+ if (lgen != nullptr) {
return lgen->ConvertToOutputFormat(this->NinjaCommand,
cmOutputConverter::SHELL);
}
@@ -1487,44 +1462,106 @@ bool cmGlobalNinjaGenerator::SupportsMultilineDepfile() const
return this->NinjaSupportsMultilineDepfile;
}
+bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os)
+{
+ cmLocalGenerator* lgr = this->LocalGenerators.at(0);
+ std::string cleanScriptRel = "CMakeFiles/clean_additional.cmake";
+ std::string cleanScriptAbs = lgr->GetBinaryDirectory();
+ cleanScriptAbs += '/';
+ cleanScriptAbs += cleanScriptRel;
+
+ // Check if there are additional files to clean
+ if (this->AdditionalCleanFiles.empty()) {
+ // Remove cmake clean script file if it exists
+ cmSystemTools::RemoveFile(cleanScriptAbs);
+ return false;
+ }
+
+ // Write cmake clean script file
+ {
+ cmGeneratedFileStream fout(cleanScriptAbs);
+ if (!fout) {
+ return false;
+ }
+ fout << "# Additional clean files\n\n";
+ fout << "file(REMOVE_RECURSE\n";
+ for (std::string const& acf : this->AdditionalCleanFiles) {
+ fout << " "
+ << cmOutputConverter::EscapeForCMake(ConvertToNinjaPath(acf))
+ << '\n';
+ }
+ fout << ")\n";
+ }
+ // Register clean script file
+ lgr->GetMakefile()->AddCMakeOutputFile(cleanScriptAbs);
+
+ // Write rule
+ {
+ cmNinjaRule rule("CLEAN_ADDITIONAL");
+ rule.Command = CMakeCmd();
+ rule.Command += " -P ";
+ rule.Command += lgr->ConvertToOutputFormat(
+ this->NinjaOutputPath(cleanScriptRel), cmOutputConverter::SHELL);
+ rule.Description = "Cleaning additional files...";
+ rule.Comment = "Rule for cleaning additional files.";
+ WriteRule(*this->RulesFileStream, rule);
+ }
+
+ // Write build
+ {
+ cmNinjaBuild build("CLEAN_ADDITIONAL");
+ build.Comment = "Clean additional files.";
+ build.Outputs.push_back(
+ this->NinjaOutputPath(this->GetAdditionalCleanTargetName()));
+ WriteBuild(os, build);
+ }
+ // Return success
+ return true;
+}
+
void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
{
- WriteRule(*this->RulesFileStream, "CLEAN", ninjaCmd() + " -t clean",
- "Cleaning all built files...",
- "Rule for cleaning all built files.",
- /*depfile=*/"",
- /*deptype=*/"",
- /*rspfile=*/"",
- /*rspcontent*/ "",
- /*restat=*/"",
- /*generator=*/false);
- WriteBuild(os, "Clean all the built files.", "CLEAN",
- /*outputs=*/cmNinjaDeps(1, this->NinjaOutputPath("clean")),
- /*implicitOuts=*/cmNinjaDeps(),
- /*explicitDeps=*/cmNinjaDeps(),
- /*implicitDeps=*/cmNinjaDeps(),
- /*orderOnlyDeps=*/cmNinjaDeps(),
- /*variables=*/cmNinjaVars());
+ // -- Additional clean target
+ bool additionalFiles = WriteTargetCleanAdditional(os);
+
+ // -- Default clean target
+ // Write rule
+ {
+ cmNinjaRule rule("CLEAN");
+ rule.Command = NinjaCmd() + " -t clean";
+ rule.Description = "Cleaning all built files...";
+ rule.Comment = "Rule for cleaning all built files.";
+ WriteRule(*this->RulesFileStream, rule);
+ }
+
+ // Write build
+ {
+ cmNinjaBuild build("CLEAN");
+ build.Comment = "Clean all the built files.";
+ build.Outputs.push_back(this->NinjaOutputPath(this->GetCleanTargetName()));
+ if (additionalFiles) {
+ build.ExplicitDeps.push_back(
+ this->NinjaOutputPath(this->GetAdditionalCleanTargetName()));
+ }
+ WriteBuild(os, build);
+ }
}
void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os)
{
- WriteRule(*this->RulesFileStream, "HELP", ninjaCmd() + " -t targets",
- "All primary targets available:",
- "Rule for printing all primary targets available.",
- /*depfile=*/"",
- /*deptype=*/"",
- /*rspfile=*/"",
- /*rspcontent*/ "",
- /*restat=*/"",
- /*generator=*/false);
- WriteBuild(os, "Print all primary targets available.", "HELP",
- /*outputs=*/cmNinjaDeps(1, this->NinjaOutputPath("help")),
- /*implicitOuts=*/cmNinjaDeps(),
- /*explicitDeps=*/cmNinjaDeps(),
- /*implicitDeps=*/cmNinjaDeps(),
- /*orderOnlyDeps=*/cmNinjaDeps(),
- /*variables=*/cmNinjaVars());
+ {
+ cmNinjaRule rule("HELP");
+ rule.Command = NinjaCmd() + " -t targets";
+ rule.Description = "All primary targets available:";
+ rule.Comment = "Rule for printing all primary targets available.";
+ WriteRule(*this->RulesFileStream, rule);
+ }
+ {
+ cmNinjaBuild build("HELP");
+ build.Comment = "Print all primary targets available.";
+ build.Outputs.push_back(this->NinjaOutputPath("help"));
+ WriteBuild(os, build);
+ }
}
void cmGlobalNinjaGenerator::InitOutputPathPrefix()
@@ -1573,12 +1610,13 @@ Compilation of source files within a target is split into the following steps:
command = gfortran -cpp $DEFINES $INCLUDES $FLAGS -E $in -o $out &&
cmake -E cmake_ninja_depends \
--tdi=FortranDependInfo.json --pp=$out --dep=$DEP_FILE \
- --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE
+ --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE \
+ --lang=Fortran
- build src.f90-pp.f90 | src.f90-pp.f90.ddi: Fortran_PREPROCESS src.f90
+ build src.f90-pp.f90 | src.f90.o.ddi: Fortran_PREPROCESS src.f90
OBJ_FILE = src.f90.o
- DEP_FILE = src.f90-pp.f90.d
- DYNDEP_INTERMEDIATE_FILE = src.f90-pp.f90.ddi
+ DEP_FILE = src.f90.o.d
+ DYNDEP_INTERMEDIATE_FILE = src.f90.o.ddi
The ``cmake -E cmake_ninja_depends`` tool reads the preprocessed output
and generates the ninja depfile for preprocessor dependencies. It also
@@ -1592,9 +1630,9 @@ Compilation of source files within a target is split into the following steps:
rule Fortran_DYNDEP
command = cmake -E cmake_ninja_dyndep \
- --tdi=FortranDependInfo.json --dd=$out $in
+ --tdi=FortranDependInfo.json --lang=Fortran --dd=$out $in
- build Fortran.dd: Fortran_DYNDEP src1.f90-pp.f90.ddi src2.f90-pp.f90.ddi
+ build Fortran.dd: Fortran_DYNDEP src1.f90.o.ddi src2.f90.o.ddi
The ``cmake -E cmake_ninja_dyndep`` tool reads the "ddi" files from all
sources in the target and the ``FortranModules.json`` files from targets
@@ -1632,6 +1670,19 @@ Compilation of source files within a target is split into the following steps:
(because the latter consumes the module).
*/
+struct cmSourceInfo
+{
+ // Set of provided and required modules.
+ std::set<std::string> Provides;
+ std::set<std::string> Requires;
+
+ // Set of files included in the translation unit.
+ std::set<std::string> Includes;
+};
+
+static std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
+ std::string const& arg_tdi, std::string const& arg_pp);
+
int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
std::vector<std::string>::const_iterator argEnd)
{
@@ -1640,8 +1691,8 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
std::string arg_dep;
std::string arg_obj;
std::string arg_ddi;
- for (std::vector<std::string>::const_iterator a = argBeg; a != argEnd; ++a) {
- std::string const& arg = *a;
+ std::string arg_lang;
+ for (std::string const& arg : cmMakeRange(argBeg, argEnd)) {
if (cmHasLiteralPrefix(arg, "--tdi=")) {
arg_tdi = arg.substr(6);
} else if (cmHasLiteralPrefix(arg, "--pp=")) {
@@ -1652,9 +1703,10 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
arg_obj = arg.substr(6);
} else if (cmHasLiteralPrefix(arg, "--ddi=")) {
arg_ddi = arg.substr(6);
+ } else if (cmHasLiteralPrefix(arg, "--lang=")) {
+ arg_lang = arg.substr(7);
} else {
- cmSystemTools::Error("-E cmake_ninja_depends unknown argument: ",
- arg.c_str());
+ cmSystemTools::Error("-E cmake_ninja_depends unknown argument: " + arg);
return 1;
}
}
@@ -1678,7 +1730,61 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
cmSystemTools::Error("-E cmake_ninja_depends requires value for --ddi=");
return 1;
}
+ if (arg_lang.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_depends requires value for --lang=");
+ return 1;
+ }
+
+ std::unique_ptr<cmSourceInfo> info;
+ if (arg_lang == "Fortran") {
+ info = cmcmd_cmake_ninja_depends_fortran(arg_tdi, arg_pp);
+ } else {
+ cmSystemTools::Error("-E cmake_ninja_depends does not understand the " +
+ arg_lang + " language");
+ return 1;
+ }
+
+ if (!info) {
+ // The error message is already expected to have been output.
+ return 1;
+ }
+
+ {
+ cmGeneratedFileStream depfile(arg_dep);
+ depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":";
+ for (std::string const& include : info->Includes) {
+ depfile << " \\\n " << cmSystemTools::ConvertToUnixOutputPath(include);
+ }
+ depfile << "\n";
+ }
+
+ Json::Value ddi(Json::objectValue);
+ ddi["object"] = arg_obj;
+
+ Json::Value& ddi_provides = ddi["provides"] = Json::arrayValue;
+ for (std::string const& provide : info->Provides) {
+ ddi_provides.append(provide);
+ }
+ Json::Value& ddi_requires = ddi["requires"] = Json::arrayValue;
+ for (std::string const& r : info->Requires) {
+ // Require modules not provided in the same source.
+ if (!info->Provides.count(r)) {
+ ddi_requires.append(r);
+ }
+ }
+
+ cmGeneratedFileStream ddif(arg_ddi);
+ ddif << ddi;
+ if (!ddif) {
+ cmSystemTools::Error("-E cmake_ninja_depends failed to write " + arg_ddi);
+ return 1;
+ }
+ return 0;
+}
+std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
+ std::string const& arg_tdi, std::string const& arg_pp)
+{
cmFortranCompiler fc;
std::vector<std::string> includes;
{
@@ -1688,10 +1794,9 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
cmsys::ifstream tdif(arg_tdi.c_str(), std::ios::in | std::ios::binary);
Json::Reader reader;
if (!reader.parse(tdif, tdio, false)) {
- cmSystemTools::Error("-E cmake_ninja_depends failed to parse ",
- arg_tdi.c_str(),
- reader.getFormattedErrorMessages().c_str());
- return 1;
+ cmSystemTools::Error("-E cmake_ninja_depends failed to parse " +
+ arg_tdi + reader.getFormattedErrorMessages());
+ return nullptr;
}
}
@@ -1712,54 +1817,26 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
fc.SModExt = tdi_submodule_ext.asString();
}
- cmFortranSourceInfo info;
+ cmFortranSourceInfo finfo;
std::set<std::string> defines;
- cmFortranParser parser(fc, includes, defines, info);
+ cmFortranParser parser(fc, includes, defines, finfo);
if (!cmFortranParser_FilePush(&parser, arg_pp.c_str())) {
- cmSystemTools::Error("-E cmake_ninja_depends failed to open ",
- arg_pp.c_str());
- return 1;
+ cmSystemTools::Error("-E cmake_ninja_depends failed to open " + arg_pp);
+ return nullptr;
}
if (cmFortran_yyparse(parser.Scanner) != 0) {
// Failed to parse the file.
- return 1;
- }
-
- {
- cmGeneratedFileStream depfile(arg_dep);
- depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":";
- for (std::string const& include : info.Includes) {
- depfile << " \\\n " << cmSystemTools::ConvertToUnixOutputPath(include);
- }
- depfile << "\n";
+ return nullptr;
}
- Json::Value ddi(Json::objectValue);
- ddi["object"] = arg_obj;
-
- Json::Value& ddi_provides = ddi["provides"] = Json::arrayValue;
- for (std::string const& provide : info.Provides) {
- ddi_provides.append(provide);
- }
- Json::Value& ddi_requires = ddi["requires"] = Json::arrayValue;
- for (std::string const& r : info.Requires) {
- // Require modules not provided in the same source.
- if (!info.Provides.count(r)) {
- ddi_requires.append(r);
- }
- }
-
- cmGeneratedFileStream ddif(arg_ddi);
- ddif << ddi;
- if (!ddif) {
- cmSystemTools::Error("-E cmake_ninja_depends failed to write ",
- arg_ddi.c_str());
- return 1;
- }
- return 0;
+ auto info = cm::make_unique<cmSourceInfo>();
+ info->Provides = finfo.Provides;
+ info->Requires = finfo.Requires;
+ info->Includes = finfo.Includes;
+ return info;
}
-struct cmFortranObjectInfo
+struct cmDyndepObjectInfo
{
std::string Object;
std::vector<std::string> Provides;
@@ -1771,7 +1848,8 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
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::vector<std::string> const& linked_target_dirs,
+ std::string const& arg_lang)
{
// Setup path conversions.
{
@@ -1788,7 +1866,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
this->LocalGenerators.push_back(lgd.release());
}
- std::vector<cmFortranObjectInfo> objects;
+ std::vector<cmDyndepObjectInfo> objects;
for (std::string const& arg_ddi : arg_ddis) {
// Load the ddi file and compute the module file paths it provides.
Json::Value ddio;
@@ -1796,13 +1874,12 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
cmsys::ifstream ddif(arg_ddi.c_str(), std::ios::in | std::ios::binary);
Json::Reader reader;
if (!reader.parse(ddif, ddio, false)) {
- cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse ",
- arg_ddi.c_str(),
- reader.getFormattedErrorMessages().c_str());
+ cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse " + arg_ddi +
+ reader.getFormattedErrorMessages());
return false;
}
- cmFortranObjectInfo info;
+ cmDyndepObjectInfo info;
info.Object = ddi["object"].asString();
Json::Value const& ddi_provides = ddi["provides"];
if (ddi_provides.isArray()) {
@@ -1824,14 +1901,15 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
// Populate the module map with those provided by linked targets first.
for (std::string const& linked_target_dir : linked_target_dirs) {
- std::string const ltmn = linked_target_dir + "/FortranModules.json";
+ std::string const ltmn =
+ linked_target_dir + "/" + arg_lang + "Modules.json";
Json::Value ltm;
cmsys::ifstream ltmf(ltmn.c_str(), std::ios::in | std::ios::binary);
Json::Reader reader;
if (ltmf && !reader.parse(ltmf, ltm, false)) {
- cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse ",
- linked_target_dir.c_str(),
- reader.getFormattedErrorMessages().c_str());
+ cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse " +
+ linked_target_dir +
+ reader.getFormattedErrorMessages());
return false;
}
if (ltm.isObject()) {
@@ -1845,7 +1923,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
// 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;
- for (cmFortranObjectInfo const& object : objects) {
+ for (cmDyndepObjectInfo const& object : objects) {
for (std::string const& p : object.Provides) {
std::string const mod = module_dir + p;
mod_files[p] = mod;
@@ -1856,38 +1934,35 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
cmGeneratedFileStream ddf(arg_dd);
ddf << "ninja_dyndep_version = 1.0\n";
- for (cmFortranObjectInfo const& object : objects) {
- std::string const ddComment;
- std::string const ddRule = "dyndep";
- cmNinjaDeps ddOutputs;
- cmNinjaDeps ddImplicitOuts;
- cmNinjaDeps ddExplicitDeps;
- cmNinjaDeps ddImplicitDeps;
- cmNinjaDeps ddOrderOnlyDeps;
- cmNinjaVars ddVars;
-
- ddOutputs.push_back(object.Object);
- for (std::string const& p : object.Provides) {
- ddImplicitOuts.push_back(this->ConvertToNinjaPath(mod_files[p]));
- }
- for (std::string const& r : object.Requires) {
- std::map<std::string, std::string>::iterator m = mod_files.find(r);
- if (m != mod_files.end()) {
- ddImplicitDeps.push_back(this->ConvertToNinjaPath(m->second));
+ {
+ cmNinjaBuild build("dyndep");
+ build.Outputs.emplace_back("");
+ for (cmDyndepObjectInfo const& object : objects) {
+ build.Outputs[0] = object.Object;
+ build.ImplicitOuts.clear();
+ for (std::string const& p : object.Provides) {
+ build.ImplicitOuts.push_back(this->ConvertToNinjaPath(mod_files[p]));
+ }
+ build.ImplicitDeps.clear();
+ for (std::string const& r : object.Requires) {
+ auto mit = mod_files.find(r);
+ if (mit != mod_files.end()) {
+ build.ImplicitDeps.push_back(this->ConvertToNinjaPath(mit->second));
+ }
+ }
+ build.Variables.clear();
+ if (!object.Provides.empty()) {
+ build.Variables.emplace("restat", "1");
}
- }
- if (!object.Provides.empty()) {
- ddVars["restat"] = "1";
- }
- this->WriteBuild(ddf, ddComment, ddRule, ddOutputs, ddImplicitOuts,
- ddExplicitDeps, ddImplicitDeps, ddOrderOnlyDeps, ddVars);
+ this->WriteBuild(ddf, build);
+ }
}
// 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 =
- cmSystemTools::GetFilenamePath(arg_dd) + "/FortranModules.json";
+ cmSystemTools::GetFilenamePath(arg_dd) + "/" + arg_lang + "Modules.json";
cmGeneratedFileStream tmf(target_mods_file);
tmf << tm;
@@ -1901,19 +1976,21 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
cmSystemTools::HandleResponseFile(argBeg, argEnd);
std::string arg_dd;
+ std::string arg_lang;
std::string arg_tdi;
std::vector<std::string> arg_ddis;
for (std::string const& arg : arg_full) {
if (cmHasLiteralPrefix(arg, "--tdi=")) {
arg_tdi = arg.substr(6);
+ } else if (cmHasLiteralPrefix(arg, "--lang=")) {
+ arg_lang = arg.substr(7);
} else if (cmHasLiteralPrefix(arg, "--dd=")) {
arg_dd = arg.substr(5);
} else if (!cmHasLiteralPrefix(arg, "--") &&
cmHasLiteralSuffix(arg, ".ddi")) {
arg_ddis.push_back(arg);
} else {
- cmSystemTools::Error("-E cmake_ninja_dyndep unknown argument: ",
- arg.c_str());
+ cmSystemTools::Error("-E cmake_ninja_dyndep unknown argument: " + arg);
return 1;
}
}
@@ -1921,6 +1998,10 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --tdi=");
return 1;
}
+ if (arg_lang.empty()) {
+ cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --lang=");
+ return 1;
+ }
if (arg_dd.empty()) {
cmSystemTools::Error("-E cmake_ninja_dyndep requires value for --dd=");
return 1;
@@ -1932,9 +2013,8 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
cmsys::ifstream tdif(arg_tdi.c_str(), std::ios::in | std::ios::binary);
Json::Reader reader;
if (!reader.parse(tdif, tdio, false)) {
- cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse ",
- arg_tdi.c_str(),
- reader.getFormattedErrorMessages().c_str());
+ cmSystemTools::Error("-E cmake_ninja_dyndep failed to parse " + arg_tdi +
+ reader.getFormattedErrorMessages());
return 1;
}
}
@@ -1944,7 +2024,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
std::string const dir_top_bld = tdi["dir-top-bld"].asString();
std::string const dir_top_src = tdi["dir-top-src"].asString();
std::string module_dir = tdi["module-dir"].asString();
- if (!module_dir.empty()) {
+ if (!module_dir.empty() && !cmHasLiteralSuffix(module_dir, "/")) {
module_dir += "/";
}
std::vector<std::string> linked_target_dirs;
@@ -1962,8 +2042,8 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
static_cast<cmGlobalNinjaGenerator*>(cm.CreateGlobalGenerator("Ninja")));
if (!ggd ||
!ggd->WriteDyndepFile(dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld,
- arg_dd, arg_ddis, module_dir,
- linked_target_dirs)) {
+ arg_dd, arg_ddis, module_dir, linked_target_dirs,
+ arg_lang)) {
return 1;
}
return 0;
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 226b73dfd..15dd4044e 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -7,12 +7,15 @@
#include <iosfwd>
#include <map>
+#include <memory> // IWYU pragma: keep
#include <set>
#include <string>
#include <unordered_map>
+#include <unordered_set>
#include <utility>
#include <vector>
+#include "cmGeneratedFileStream.h"
#include "cmGlobalCommonGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalGeneratorFactory.h"
@@ -21,7 +24,6 @@
#include "cm_codecvt.hxx"
class cmCustomCommand;
-class cmGeneratedFileStream;
class cmGeneratorTarget;
class cmLinkLineComputer;
class cmLocalGenerator;
@@ -41,8 +43,6 @@ struct cmDocumentationEntry;
* it is handle by Ninja's -v option.
* - We don't care about computing any progress status since Ninja manages
* it itself.
- * - We don't care about generating a clean target since Ninja already have
- * a clean tool.
* - We generate one build.ninja and one rules.ninja per project.
* - We try to minimize the number of generated rules: one per target and
* language.
@@ -101,54 +101,27 @@ public:
bool IsIPOSupported() const override { return true; }
/**
- * Write a build statement to @a os with the @a comment using
- * the @a rule the list of @a outputs files and inputs.
- * It also writes the variables bound to this build statement.
+ * Write a build statement @a build to @a os.
* @warning no escaping of any kind is done here.
*/
- void WriteBuild(std::ostream& os, const std::string& comment,
- const std::string& rule, const cmNinjaDeps& outputs,
- const cmNinjaDeps& implicitOuts,
- const cmNinjaDeps& explicitDeps,
- const cmNinjaDeps& implicitDeps,
- const cmNinjaDeps& orderOnlyDeps,
- const cmNinjaVars& variables,
- const std::string& rspfile = std::string(),
+ void WriteBuild(std::ostream& os, cmNinjaBuild const& build,
int cmdLineLimit = 0, bool* usedResponseFile = nullptr);
- /**
- * Helper to write a build statement with the special 'phony' rule.
- */
- void WritePhonyBuild(std::ostream& os, const std::string& comment,
- const cmNinjaDeps& outputs,
- const cmNinjaDeps& explicitDeps,
- const cmNinjaDeps& implicitDeps = cmNinjaDeps(),
- const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps(),
- const cmNinjaVars& variables = cmNinjaVars());
-
- void WriteCustomCommandBuild(const std::string& command,
- const std::string& description,
- const std::string& comment,
- const std::string& depfile, bool uses_terminal,
- bool restat, const cmNinjaDeps& outputs,
- const cmNinjaDeps& deps = cmNinjaDeps(),
- const cmNinjaDeps& orderOnly = cmNinjaDeps());
- void WriteMacOSXContentBuild(const std::string& input,
- const std::string& output);
+ void WriteCustomCommandBuild(
+ const std::string& command, const std::string& description,
+ const std::string& comment, const std::string& depfile,
+ const std::string& pool, bool uses_terminal, bool restat,
+ const cmNinjaDeps& outputs,
+ const cmNinjaDeps& explicitDeps = cmNinjaDeps(),
+ const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps());
+
+ void WriteMacOSXContentBuild(std::string input, std::string output);
/**
- * Write a rule statement named @a name to @a os with the @a comment,
- * the mandatory @a command, the @a depfile and the @a description.
- * It also writes the variables bound to this rule statement.
+ * Write a rule statement to @a os.
* @warning no escaping of any kind is done here.
*/
- static void WriteRule(std::ostream& os, const std::string& name,
- const std::string& command,
- const std::string& description,
- const std::string& comment, const std::string& depfile,
- const std::string& deptype, const std::string& rspfile,
- const std::string& rspcontent,
- const std::string& restat, bool generator);
+ static void WriteRule(std::ostream& os, cmNinjaRule const& rule);
/**
* Write a variable named @a name to @a os with value @a value and an
@@ -200,15 +173,12 @@ public:
void EnableLanguage(std::vector<std::string> const& languages,
cmMakefile* mf, bool optional) override;
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
// Setup target names
const char* GetAllTargetName() const override { return "all"; }
@@ -236,12 +206,12 @@ public:
cmGeneratedFileStream* GetBuildFileStream() const
{
- return this->BuildFileStream;
+ return this->BuildFileStream.get();
}
cmGeneratedFileStream* GetRulesFileStream() const
{
- return this->RulesFileStream;
+ return this->RulesFileStream.get();
}
std::string const& ConvertToNinjaPath(const std::string& path) const;
@@ -260,6 +230,13 @@ public:
};
MapToNinjaPathImpl MapToNinjaPath() { return MapToNinjaPathImpl(this); }
+ // -- Additional clean files
+ void AddAdditionalCleanFile(std::string fileName);
+ const char* GetAdditionalCleanTargetName() const
+ {
+ return "CMakeFiles/clean.additional";
+ }
+
void AddCXXCompileCommand(const std::string& commandLine,
const std::string& sourceFile);
@@ -268,11 +245,7 @@ public:
* Call WriteRule() behind the scene but perform some check before like:
* - Do not add twice the same rule.
*/
- void AddRule(const std::string& name, const std::string& command,
- const std::string& description, const std::string& comment,
- const std::string& depfile, const std::string& deptype,
- const std::string& rspfile, const std::string& rspcontent,
- const std::string& restat, bool generator);
+ void AddRule(cmNinjaRule const& rule);
bool HasRule(const std::string& name);
@@ -329,9 +302,9 @@ public:
return LocalGenerators;
}
- bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target)
+ bool IsExcluded(cmGeneratorTarget* target)
{
- return cmGlobalGenerator::IsExcluded(root, target);
+ return cmGlobalGenerator::IsExcluded(target);
}
int GetRuleCmdLength(const std::string& name) { return RuleCmdLength[name]; }
@@ -365,7 +338,8 @@ public:
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::vector<std::string> const& linked_target_dirs,
+ std::string const& arg_lang);
protected:
void Generate() override;
@@ -380,12 +354,12 @@ private:
cmMakefile* mf) const override;
bool CheckFortran(cmMakefile* mf) const;
- void OpenBuildFileStream();
+ bool OpenBuildFileStream();
void CloseBuildFileStream();
void CloseCompileCommandsStream();
- void OpenRulesFileStream();
+ bool OpenRulesFileStream();
void CloseRulesFileStream();
/// Write the common disclaimer text at the top of each build file.
@@ -400,6 +374,7 @@ private:
void WriteBuiltinTargets(std::ostream& os);
void WriteTargetAll(std::ostream& os);
void WriteTargetRebuildManifest(std::ostream& os);
+ bool WriteTargetCleanAdditional(std::ostream& os);
void WriteTargetClean(std::ostream& os);
void WriteTargetHelp(std::ostream& os);
@@ -407,25 +382,22 @@ private:
cmGeneratorTarget const* target,
std::set<cmGeneratorTarget const*>& depends);
- std::string ninjaCmd() const;
+ std::string CMakeCmd() const;
+ std::string NinjaCmd() const;
/// The file containing the build statement. (the relationship of the
/// compilation DAG).
- cmGeneratedFileStream* BuildFileStream;
+ std::unique_ptr<cmGeneratedFileStream> BuildFileStream;
/// The file containing the rule statements. (The action attached to each
/// edge of the compilation DAG).
- cmGeneratedFileStream* RulesFileStream;
- cmGeneratedFileStream* CompileCommandsStream;
-
- /// The type used to store the set of rules added to the generated build
- /// system.
- typedef std::set<std::string> RulesSetType;
+ std::unique_ptr<cmGeneratedFileStream> RulesFileStream;
+ std::unique_ptr<cmGeneratedFileStream> CompileCommandsStream;
/// The set of rules added to the generated build system.
- RulesSetType Rules;
+ std::unordered_set<std::string> Rules;
/// Length of rule command, used by rsp file evaluation
- std::map<std::string, int> RuleCmdLength;
+ std::unordered_map<std::string, int> RuleCmdLength;
/// The set of dependencies to add to the "all" target.
cmNinjaDeps AllDependencies;
@@ -475,6 +447,7 @@ private:
std::string OutputPathPrefix;
std::string TargetAll;
std::string CMakeCacheFile;
+ std::set<std::string> AdditionalCleanFiles;
};
#endif // ! cmGlobalNinjaGenerator_h
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index f1a128a83..aa584add7 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -57,7 +57,7 @@ void cmGlobalUnixMakefileGenerator3::EnableLanguage(
}
}
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
cmLocalGenerator* cmGlobalUnixMakefileGenerator3::CreateLocalGenerator(
cmMakefile* mf)
{
@@ -169,7 +169,7 @@ void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand(
{
if (this->CommandDatabase == nullptr) {
std::string commandDatabaseName =
- std::string(this->GetCMakeInstance()->GetHomeOutputDirectory()) +
+ this->GetCMakeInstance()->GetHomeOutputDirectory() +
"/compile_commands.json";
this->CommandDatabase = new cmGeneratedFileStream(commandDatabaseName);
*this->CommandDatabase << "[" << std::endl;
@@ -177,13 +177,13 @@ void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand(
*this->CommandDatabase << "," << std::endl;
}
*this->CommandDatabase << "{" << std::endl
- << " \"directory\": \""
+ << R"( "directory": ")"
<< cmGlobalGenerator::EscapeJSON(workingDirectory)
<< "\"," << std::endl
- << " \"command\": \""
+ << R"( "command": ")"
<< cmGlobalGenerator::EscapeJSON(compileCommand)
<< "\"," << std::endl
- << " \"file\": \""
+ << R"( "file": ")"
<< cmGlobalGenerator::EscapeJSON(sourceFile) << "\""
<< std::endl
<< "}";
@@ -232,28 +232,16 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
depends.push_back(this->EmptyRuleHackDepends);
}
- // Write and empty all:
- lg->WriteMakeRule(makefileStream, "The main recursive all target", "all",
- depends, no_commands, true);
-
- // Write an empty preinstall:
- lg->WriteMakeRule(makefileStream, "The main recursive preinstall target",
- "preinstall", depends, no_commands, true);
-
- // Write an empty clean:
- lg->WriteMakeRule(makefileStream, "The main recursive clean target", "clean",
- depends, no_commands, true);
-
// Write out the "special" stuff
lg->WriteSpecialTargetsTop(makefileStream);
- // write the target convenience rules
+ // Write the target convenience rules
for (cmLocalGenerator* localGen : this->LocalGenerators) {
- lg = static_cast<cmLocalUnixMakefileGenerator3*>(localGen);
- this->WriteConvenienceRules2(makefileStream, lg);
+ this->WriteConvenienceRules2(
+ makefileStream, static_cast<cmLocalUnixMakefileGenerator3*>(localGen));
}
- lg = static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]);
+ // Write special bottom targets
lg->WriteSpecialTargetsBottom(makefileStream);
}
@@ -294,11 +282,8 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
// for each cmMakefile get its list of dependencies
std::vector<std::string> lfiles;
for (cmLocalGenerator* localGen : this->LocalGenerators) {
- lg = static_cast<cmLocalUnixMakefileGenerator3*>(localGen);
-
// Get the list of files contributing to this generation step.
- lfiles.insert(lfiles.end(), lg->GetMakefile()->GetListFiles().begin(),
- lg->GetMakefile()->GetListFiles().end());
+ cmAppend(lfiles, localGen->GetMakefile()->GetListFiles());
}
cmake* cm = this->GetCMakeInstance();
@@ -354,9 +339,7 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
{
cmakefileStream << "# Byproducts of CMake generate step:\n"
<< "set(CMAKE_MAKEFILE_PRODUCTS\n";
- const std::vector<std::string>& outfiles =
- lg->GetMakefile()->GetOutputFiles();
- for (std::string const& outfile : outfiles) {
+ for (std::string const& outfile : lg->GetMakefile()->GetOutputFiles()) {
cmakefileStream << " \""
<< lg->MaybeConvertToRelativePath(binDir, outfile)
<< "\"\n";
@@ -392,8 +375,7 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefileLanguageRules(
for (cmLocalGenerator* lGenerator : lGenerators) {
lg = static_cast<cmLocalUnixMakefileGenerator3*>(lGenerator);
// for all of out targets
- const std::vector<cmGeneratorTarget*>& tgts = lg->GetGeneratorTargets();
- for (cmGeneratorTarget* tgt : tgts) {
+ for (cmGeneratorTarget* tgt : lg->GetGeneratorTargets()) {
if ((tgt->GetType() == cmStateEnums::EXECUTABLE) ||
(tgt->GetType() == cmStateEnums::STATIC_LIBRARY) ||
(tgt->GetType() == cmStateEnums::SHARED_LIBRARY) ||
@@ -413,18 +395,18 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefileLanguageRules(
void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg,
- const char* pass, bool check_all, bool check_relink)
+ const char* pass, bool check_all, bool check_relink,
+ std::vector<std::string> const& commands)
{
// Get the relative path to the subdirectory from the top.
std::string makeTarget = lg->GetCurrentBinaryDirectory();
- makeTarget += "/";
+ makeTarget += '/';
makeTarget += pass;
// The directory-level rule should depend on the target-level rules
// for all targets in the directory.
std::vector<std::string> depends;
- const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
- for (cmGeneratorTarget* gtarget : targets) {
+ for (cmGeneratorTarget* gtarget : lg->GetGeneratorTargets()) {
int type = gtarget->GetType();
if ((type == cmStateEnums::EXECUTABLE) ||
(type == cmStateEnums::STATIC_LIBRARY) ||
@@ -446,10 +428,9 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
// The directory-level rule should depend on the directory-level
// rules of the subdirectories.
- std::vector<cmStateSnapshot> children = lg->GetStateSnapshot().GetChildren();
- for (cmStateSnapshot const& c : children) {
+ for (cmStateSnapshot const& c : lg->GetStateSnapshot().GetChildren()) {
std::string subdir = c.GetDirectory().GetCurrentBinary();
- subdir += "/";
+ subdir += '/';
subdir += pass;
depends.push_back(std::move(subdir));
}
@@ -461,44 +442,58 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
}
// Write the rule.
- std::string doc = "Convenience name for \"";
- doc += pass;
- doc += "\" pass in the directory.";
- std::vector<std::string> no_commands;
- lg->WriteMakeRule(ruleFileStream, doc.c_str(), makeTarget, depends,
- no_commands, true);
+ std::string doc;
+ if (lg->IsRootMakefile()) {
+ doc = "The main recursive \"";
+ doc += pass;
+ doc += "\" target.";
+ } else {
+ doc = "Recursive \"";
+ doc += pass;
+ doc += "\" directory target.";
+ }
+ lg->WriteMakeRule(ruleFileStream, doc.c_str(), makeTarget, depends, commands,
+ true);
}
void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2(
std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg)
{
- // Only subdirectories need these rules.
- if (lg->IsRootMakefile()) {
- return;
- }
-
// Begin the directory-level rules section.
- std::string dir =
- cmSystemTools::ConvertToOutputPath(lg->MaybeConvertToRelativePath(
- lg->GetBinaryDirectory(), lg->GetCurrentBinaryDirectory()));
- lg->WriteDivider(ruleFileStream);
- ruleFileStream << "# Directory level rules for directory " << dir << "\n\n";
+ {
+ std::string dir =
+ cmSystemTools::ConvertToOutputPath(lg->MaybeConvertToRelativePath(
+ lg->GetBinaryDirectory(), lg->GetCurrentBinaryDirectory()));
+ lg->WriteDivider(ruleFileStream);
+ if (lg->IsRootMakefile()) {
+ ruleFileStream << "# Directory level rules for the build root directory";
+ } else {
+ ruleFileStream << "# Directory level rules for directory " << dir;
+ }
+ ruleFileStream << "\n\n";
+ }
// Write directory-level rules for "all".
this->WriteDirectoryRule2(ruleFileStream, lg, "all", true, false);
// Write directory-level rules for "clean".
- this->WriteDirectoryRule2(ruleFileStream, lg, "clean", false, false);
+ {
+ std::vector<std::string> cmds;
+ lg->AppendDirectoryCleanCommand(cmds);
+ this->WriteDirectoryRule2(ruleFileStream, lg, "clean", false, false, cmds);
+ }
// Write directory-level rules for "preinstall".
this->WriteDirectoryRule2(ruleFileStream, lg, "preinstall", true, true);
}
-void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& /*projectName*/, const std::string& /*projectDir*/,
- const std::string& targetName, const std::string& /*config*/, bool fast,
- int jobs, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& /*projectName*/,
+ const std::string& /*projectDir*/,
+ std::vector<std::string> const& targetNames, const std::string& /*config*/,
+ bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions)
{
std::unique_ptr<cmMakefile> mfu;
cmMakefile* mf;
@@ -515,34 +510,38 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
mf = mfu.get();
}
+ GeneratedMakeCommand makeCommand;
+
// Make it possible to set verbosity also from command line
if (verbose) {
- makeCommand.add(cmSystemTools::GetCMakeCommand());
- makeCommand.add("-E");
- makeCommand.add("env");
- makeCommand.add("VERBOSE=1");
+ makeCommand.Add(cmSystemTools::GetCMakeCommand());
+ makeCommand.Add("-E");
+ makeCommand.Add("env");
+ makeCommand.Add("VERBOSE=1");
}
- makeCommand.add(this->SelectMakeProgram(makeProgram));
+ makeCommand.Add(this->SelectMakeProgram(makeProgram));
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
- makeCommand.add("-j");
+ makeCommand.Add("-j");
if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
- makeCommand.add(std::to_string(jobs));
+ makeCommand.Add(std::to_string(jobs));
}
}
- makeCommand.add(makeOptions.begin(), makeOptions.end());
- if (!targetName.empty()) {
- std::string tname = targetName;
- if (fast) {
- tname += "/fast";
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ for (auto tname : targetNames) {
+ if (!tname.empty()) {
+ if (fast) {
+ tname += "/fast";
+ }
+ tname =
+ mf->GetStateSnapshot().GetDirectory().ConvertToRelPathIfNotContained(
+ mf->GetState()->GetBinaryDirectory(), tname);
+ cmSystemTools::ConvertToOutputSlashes(tname);
+ makeCommand.Add(std::move(tname));
}
- tname =
- mf->GetStateSnapshot().GetDirectory().ConvertToRelPathIfNotContained(
- mf->GetState()->GetBinaryDirectory(), tname);
- cmSystemTools::ConvertToOutputSlashes(tname);
- makeCommand.add(std::move(tname));
}
+ return { std::move(makeCommand) };
}
void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules(
@@ -561,8 +560,7 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules(
cmLocalUnixMakefileGenerator3* lg =
static_cast<cmLocalUnixMakefileGenerator3*>(localGen);
// for each target Generate the rule files for each target.
- const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
- for (cmGeneratorTarget* gtarget : targets) {
+ for (cmGeneratorTarget* gtarget : lg->GetGeneratorTargets()) {
// Don't emit the same rule twice (e.g. two targets with the same
// simple name)
int type = gtarget->GetType();
@@ -646,8 +644,7 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
}
// for each target Generate the rule files for each target.
- const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
- for (cmGeneratorTarget* gtarget : targets) {
+ for (cmGeneratorTarget* gtarget : lg->GetGeneratorTargets()) {
int type = gtarget->GetType();
std::string name = gtarget->GetName();
if (!name.empty() &&
@@ -687,9 +684,7 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
{
std::ostringstream progressArg;
const char* sep = "";
- std::vector<unsigned long> const& progFiles =
- this->ProgressMap[gtarget].Marks;
- for (unsigned long progFile : progFiles) {
+ for (unsigned long progFile : this->ProgressMap[gtarget].Marks) {
progressArg << sep << progFile;
sep = ",";
}
@@ -712,15 +707,6 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
lg->WriteMakeRule(ruleFileStream, "All Build rule for target.",
localName, depends, commands, true);
- // add the all/all dependency
- if (!this->IsExcluded(this->LocalGenerators[0], gtarget)) {
- depends.clear();
- depends.push_back(localName);
- commands.clear();
- lg->WriteMakeRule(ruleFileStream, "Include target in all.", "all",
- depends, commands, true);
- }
-
// Write the rule.
commands.clear();
@@ -777,7 +763,7 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
"Pre-install relink rule for target.", localName,
depends, commands, true);
- if (!this->IsExcluded(this->LocalGenerators[0], gtarget)) {
+ if (!this->IsExcluded(gtarget)) {
depends.clear();
depends.push_back(localName);
commands.clear();
@@ -797,9 +783,6 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
lg->WriteMakeRule(ruleFileStream, "clean rule for target.",
makeTargetName, depends, commands, true);
commands.clear();
- depends.push_back(makeTargetName);
- lg->WriteMakeRule(ruleFileStream, "clean rule for target.", "clean",
- depends, commands, true);
}
}
}
@@ -811,8 +794,7 @@ void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks()
this->DirectoryTargetsMap.clear();
// Loop over all targets in all local generators.
for (cmLocalGenerator* lg : this->LocalGenerators) {
- const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
- for (cmGeneratorTarget* gt : targets) {
+ for (cmGeneratorTarget* gt : lg->GetGeneratorTargets()) {
cmLocalGenerator* tlg = gt->GetLocalGenerator();
if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
@@ -835,8 +817,7 @@ void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks()
// Add dependencies of the included target. An excluded
// target may still be included if it is a dependency of a
// non-excluded target.
- TargetDependSet const& tgtdeps = this->GetTargetDirectDepends(gt);
- for (cmTargetDepend const& tgtdep : tgtdeps) {
+ for (cmTargetDepend const& tgtdep : this->GetTargetDirectDepends(gt)) {
targetSet.insert(tgtdep);
}
}
@@ -850,8 +831,7 @@ size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInTarget(
size_t count = 0;
if (emitted.insert(target).second) {
count = this->ProgressMap[target].Marks.size();
- TargetDependSet const& depends = this->GetTargetDirectDepends(target);
- for (cmTargetDepend const& depend : depends) {
+ for (cmTargetDepend const& depend : this->GetTargetDirectDepends(target)) {
if (depend->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
@@ -866,9 +846,8 @@ size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInAll(
{
size_t count = 0;
std::set<cmGeneratorTarget const*> emitted;
- std::set<cmGeneratorTarget const*> const& targets =
- this->DirectoryTargetsMap[lg->GetStateSnapshot()];
- for (cmGeneratorTarget const* target : targets) {
+ for (cmGeneratorTarget const* target :
+ this->DirectoryTargetsMap[lg->GetStateSnapshot()]) {
count += this->CountProgressMarksInTarget(target, emitted);
}
return count;
@@ -907,8 +886,7 @@ void cmGlobalUnixMakefileGenerator3::TargetProgress::WriteProgressVariables(
void cmGlobalUnixMakefileGenerator3::AppendGlobalTargetDepends(
std::vector<std::string>& depends, cmGeneratorTarget* target)
{
- TargetDependSet const& depends_set = this->GetTargetDirectDepends(target);
- for (cmTargetDepend const& i : depends_set) {
+ for (cmTargetDepend const& i : this->GetTargetDirectDepends(target)) {
// Create the target-level dependency.
cmGeneratorTarget const* dep = i;
if (dep->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
@@ -950,9 +928,7 @@ void cmGlobalUnixMakefileGenerator3::WriteHelpRule(
// the targets
if (lg2 == lg || lg->IsRootMakefile()) {
// for each target Generate the rule files for each target.
- const std::vector<cmGeneratorTarget*>& targets =
- lg2->GetGeneratorTargets();
- for (cmGeneratorTarget* target : targets) {
+ for (cmGeneratorTarget* target : lg2->GetGeneratorTargets()) {
cmStateEnums::TargetType type = target->GetType();
if ((type == cmStateEnums::EXECUTABLE) ||
(type == cmStateEnums::STATIC_LIBRARY) ||
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index 8a80acc05..287472c81 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -67,7 +67,7 @@ public:
cmGlobalUnixMakefileGenerator3>();
}
- ///! Get the name for the generator.
+ //! Get the name for the generator.
std::string GetName() const override
{
return cmGlobalUnixMakefileGenerator3::GetActualName();
@@ -127,15 +127,12 @@ public:
std::string GetEmptyRuleHackDepends() { return this->EmptyRuleHackDepends; }
// change the build command for speed
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
/** Record per-target progress information. */
void RecordTargetProgress(cmMakefileTargetGenerator* tg);
@@ -168,7 +165,8 @@ protected:
void WriteDirectoryRule2(std::ostream& ruleFileStream,
cmLocalUnixMakefileGenerator3* lg, const char* pass,
- bool check_all, bool check_relink);
+ bool check_all, bool check_relink,
+ std::vector<std::string> const& commands = {});
void WriteDirectoryRules2(std::ostream& ruleFileStream,
cmLocalUnixMakefileGenerator3* lg);
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index d8b2e892c..55374a48e 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -509,7 +509,7 @@ std::string cmGlobalVisualStudio10Generator::SelectWindowsCEToolset() const
return "";
}
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
cmLocalGenerator* cmGlobalVisualStudio10Generator::CreateLocalGenerator(
cmMakefile* mf)
{
@@ -784,11 +784,11 @@ bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf)
if (this->GetSystemName() == "WindowsPhone") {
cmXMLElement(epg, "ApplicationType").Content("Windows Phone");
cmXMLElement(epg, "ApplicationTypeRevision")
- .Content(this->GetSystemVersion());
+ .Content(this->GetApplicationTypeRevision());
} else if (this->GetSystemName() == "WindowsStore") {
cmXMLElement(epg, "ApplicationType").Content("Windows Store");
cmXMLElement(epg, "ApplicationTypeRevision")
- .Content(this->GetSystemVersion());
+ .Content(this->GetApplicationTypeRevision());
}
if (!this->WindowsTargetPlatformVersion.empty()) {
cmXMLElement(epg, "WindowsTargetPlatformVersion")
@@ -878,12 +878,14 @@ bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf)
return true;
}
-void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& projectDir,
- const std::string& targetName, const std::string& config, bool fast,
- int jobs, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalVisualStudio10Generator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions)
{
+ std::vector<GeneratedMakeCommand> makeCommands;
// Select the caller- or user-preferred make program, else MSBuild.
std::string makeProgramSelected =
this->SelectMakeProgram(makeProgram, this->GetMSBuildCommand());
@@ -895,7 +897,7 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
makeProgramLower.find("vcexpress") != std::string::npos);
// Workaround to convince VCExpress.exe to produce output.
- makeCommand.RequiresOutputForward =
+ const bool requiresOutputForward =
(makeProgramLower.find("vcexpress") != std::string::npos);
// MSBuild is preferred (and required for VS Express), but if the .sln has
@@ -913,10 +915,11 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
if (parser.ParseFile(slnFile, slnData,
cmVisualStudioSlnParser::DataGroupProjects)) {
std::vector<cmSlnProjectEntry> slnProjects = slnData.GetProjects();
- for (std::vector<cmSlnProjectEntry>::const_iterator i =
- slnProjects.cbegin();
- !useDevEnv && i != slnProjects.cend(); ++i) {
- std::string proj = i->GetRelativePath();
+ for (cmSlnProjectEntry const& project : slnProjects) {
+ if (useDevEnv) {
+ break;
+ }
+ std::string proj = project.GetRelativePath();
if (proj.size() > 7 && proj.substr(proj.size() - 7) == ".vfproj") {
useDevEnv = true;
}
@@ -925,62 +928,71 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
}
if (useDevEnv) {
// Use devenv to build solutions containing Intel Fortran projects.
- cmGlobalVisualStudio7Generator::GenerateBuildCommand(
- makeCommand, makeProgram, projectName, projectDir, targetName, config,
- fast, jobs, verbose, makeOptions);
- return;
- }
+ return cmGlobalVisualStudio7Generator::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast, jobs,
+ verbose, makeOptions);
+ }
+
+ std::vector<std::string> realTargetNames = targetNames;
+ if (targetNames.empty() ||
+ ((targetNames.size() == 1) && targetNames.front().empty())) {
+ realTargetNames = { "ALL_BUILD" };
+ }
+ for (const auto& tname : realTargetNames) {
+ // msbuild.exe CxxOnly.sln /t:Build /p:Configuration=Debug
+ // /target:ALL_BUILD
+ // /m
+ if (tname.empty()) {
+ continue;
+ }
- makeCommand.add(makeProgramSelected);
+ GeneratedMakeCommand makeCommand;
+ makeCommand.RequiresOutputForward = requiresOutputForward;
+ makeCommand.Add(makeProgramSelected);
- std::string realTarget = targetName;
- // msbuild.exe CxxOnly.sln /t:Build /p:Configuration=Debug /target:ALL_BUILD
- // /m
- if (realTarget.empty()) {
- realTarget = "ALL_BUILD";
- }
- if (realTarget == "clean") {
- makeCommand.add(std::string(projectName) + ".sln");
- makeCommand.add("/t:Clean");
- } else {
- std::string targetProject(realTarget);
- targetProject += ".vcxproj";
- if (targetProject.find('/') == std::string::npos) {
- // it might be in a subdir
- if (cmSlnProjectEntry const* proj =
- slnData.GetProjectByName(realTarget)) {
- targetProject = proj->GetRelativePath();
- cmSystemTools::ConvertToUnixSlashes(targetProject);
+ if (tname == "clean") {
+ makeCommand.Add(std::string(projectName) + ".sln");
+ makeCommand.Add("/t:Clean");
+ } else {
+ std::string targetProject(tname);
+ targetProject += ".vcxproj";
+ if (targetProject.find('/') == std::string::npos) {
+ // it might be in a subdir
+ if (cmSlnProjectEntry const* proj = slnData.GetProjectByName(tname)) {
+ targetProject = proj->GetRelativePath();
+ cmSystemTools::ConvertToUnixSlashes(targetProject);
+ }
}
+ makeCommand.Add(std::move(targetProject));
}
- makeCommand.add(std::move(targetProject));
- }
- std::string configArg = "/p:Configuration=";
- if (!config.empty()) {
- configArg += config;
- } else {
- configArg += "Debug";
- }
- makeCommand.add(configArg);
- makeCommand.add(std::string("/p:Platform=") + this->GetPlatformName());
- makeCommand.add(std::string("/p:VisualStudioVersion=") +
- this->GetIDEVersion());
-
- if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
- if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
- makeCommand.add("/m");
+ std::string configArg = "/p:Configuration=";
+ if (!config.empty()) {
+ configArg += config;
} else {
- makeCommand.add(std::string("/m:") + std::to_string(jobs));
+ configArg += "Debug";
+ }
+ makeCommand.Add(configArg);
+ makeCommand.Add(std::string("/p:Platform=") + this->GetPlatformName());
+ makeCommand.Add(std::string("/p:VisualStudioVersion=") +
+ this->GetIDEVersion());
+
+ if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
+ if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
+ makeCommand.Add("/m");
+ } else {
+ makeCommand.Add(std::string("/m:") + std::to_string(jobs));
+ }
+ // Having msbuild.exe and cl.exe using multiple jobs is discouraged
+ makeCommand.Add("/p:CL_MPCount=1");
}
- // Having msbuild.exe and cl.exe using multiple jobs is discouraged
- makeCommand.add("/p:CL_MPCount=1");
- }
-
- // Respect the verbosity: 'n' normal will show build commands
- // 'm' minimal only the build step's title
- makeCommand.add(std::string("/v:") + ((verbose) ? "n" : "m"));
- makeCommand.add(makeOptions.begin(), makeOptions.end());
+ // Respect the verbosity: 'n' normal will show build commands
+ // 'm' minimal only the build step's title
+ makeCommand.Add(std::string("/v:") + ((verbose) ? "n" : "m"));
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ makeCommands.emplace_back(std::move(makeCommand));
+ }
+ return makeCommands;
}
bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
@@ -1005,7 +1017,7 @@ bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
winSDK_7_1)) {
std::ostringstream m;
m << "Found Windows SDK v7.1: " << winSDK_7_1;
- mf->DisplayStatus(m.str().c_str(), -1);
+ mf->DisplayStatus(m.str(), -1);
this->DefaultPlatformToolset = "Windows7.1SDK";
return true;
} else {
@@ -1100,6 +1112,15 @@ std::string cmGlobalVisualStudio10Generator::GetInstalledNsightTegraVersion()
return version;
}
+std::string cmGlobalVisualStudio10Generator::GetApplicationTypeRevision() const
+{
+ // Return the first two '.'-separated components of the Windows version.
+ std::string::size_type end1 = this->SystemVersion.find('.');
+ std::string::size_type end2 =
+ end1 == std::string::npos ? end1 : this->SystemVersion.find('.', end1 + 1);
+ return this->SystemVersion.substr(0, end2);
+}
+
static std::string cmLoadFlagTableString(Json::Value entry, const char* field)
{
if (entry.isMember(field)) {
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index 3ef7abfd0..1d30cd6b3 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -22,17 +22,14 @@ public:
bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override;
bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) override;
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
-
- ///! create the correct local generator
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
+
+ //! create the correct local generator
cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
/**
@@ -113,6 +110,9 @@ public:
static std::string GetInstalledNsightTegraVersion();
+ /** Return the first two components of CMAKE_SYSTEM_VERSION. */
+ std::string GetApplicationTypeRevision() const;
+
cmIDEFlagTable const* GetClFlagTable() const;
cmIDEFlagTable const* GetCSharpFlagTable() const;
cmIDEFlagTable const* GetRcFlagTable() const;
diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx
index 4eb78ba9c..4b74ef1b2 100644
--- a/Source/cmGlobalVisualStudio11Generator.cxx
+++ b/Source/cmGlobalVisualStudio11Generator.cxx
@@ -252,15 +252,10 @@ cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs()
return ret;
}
-bool cmGlobalVisualStudio11Generator::NeedsDeploy(
- cmStateEnums::TargetType type) const
+bool cmGlobalVisualStudio11Generator::TargetSystemSupportsDeployment() const
{
- if ((type == cmStateEnums::EXECUTABLE ||
- type == cmStateEnums::SHARED_LIBRARY) &&
- (this->SystemIsWindowsPhone || this->SystemIsWindowsStore)) {
- return true;
- }
- return cmGlobalVisualStudio10Generator::NeedsDeploy(type);
+ return this->SystemIsWindowsPhone || this->SystemIsWindowsStore ||
+ cmGlobalVisualStudio10Generator::TargetSystemSupportsDeployment();
}
bool cmGlobalVisualStudio11Generator::IsWindowsDesktopToolsetInstalled() const
diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h
index 8b4c8b739..f8cce1898 100644
--- a/Source/cmGlobalVisualStudio11Generator.h
+++ b/Source/cmGlobalVisualStudio11Generator.h
@@ -45,8 +45,8 @@ protected:
bool UseFolderProperty() const override;
static std::set<std::string> GetInstalledWindowsCESDKs();
- /** Return true if the configuration needs to be deployed */
- bool NeedsDeploy(cmStateEnums::TargetType type) const override;
+ /** Return true if target system supports debugging deployment. */
+ bool TargetSystemSupportsDeployment() const override;
private:
class Factory;
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
index 20258678a..6509b5616 100644
--- a/Source/cmGlobalVisualStudio14Generator.cxx
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -179,7 +179,7 @@ void cmGlobalVisualStudio14Generator::SetWindowsTargetPlatformVersion(
std::ostringstream e;
e << "Selecting Windows SDK version " << this->WindowsTargetPlatformVersion
<< " to target Windows " << this->SystemVersion << ".";
- mf->DisplayStatus(e.str().c_str(), -1);
+ mf->DisplayStatus(e.str(), -1);
}
mf->AddDefinition("CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION",
this->WindowsTargetPlatformVersion.c_str());
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index d138c1e78..8764ee439 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -45,7 +45,6 @@ cmGlobalVisualStudio7Generator::cmGlobalVisualStudio7Generator(
cmake* cm, std::string const& platformInGeneratorName)
: cmGlobalVisualStudioGenerator(cm, platformInGeneratorName)
{
- this->IntelProjectVersion = 0;
this->DevEnvCommandInitialized = false;
this->MasmEnabled = false;
this->NasmEnabled = false;
@@ -54,21 +53,20 @@ cmGlobalVisualStudio7Generator::cmGlobalVisualStudio7Generator(
cmGlobalVisualStudio7Generator::~cmGlobalVisualStudio7Generator()
{
- free(this->IntelProjectVersion);
}
// Package GUID of Intel Visual Fortran plugin to VS IDE
#define CM_INTEL_PLUGIN_GUID "{B68A201D-CB9B-47AF-A52F-7EEC72E217E4}"
-const char* cmGlobalVisualStudio7Generator::GetIntelProjectVersion()
+const std::string& cmGlobalVisualStudio7Generator::GetIntelProjectVersion()
{
- if (!this->IntelProjectVersion) {
+ if (this->IntelProjectVersion.empty()) {
// Compute the version of the Intel plugin to the VS IDE.
// If the key does not exist then use a default guess.
std::string intelVersion;
std::string vskey = this->GetRegistryBase();
vskey += "\\Packages\\" CM_INTEL_PLUGIN_GUID ";ProductVersion";
- cmSystemTools::ReadRegistryValue(vskey.c_str(), intelVersion,
+ cmSystemTools::ReadRegistryValue(vskey, intelVersion,
cmSystemTools::KeyWOW64_32);
unsigned int intelVersionNumber = ~0u;
sscanf(intelVersion.c_str(), "%u", &intelVersionNumber);
@@ -81,7 +79,7 @@ const char* cmGlobalVisualStudio7Generator::GetIntelProjectVersion()
} else {
// Version <= 9: use ProductVersion from registry.
}
- this->IntelProjectVersion = strdup(intelVersion.c_str());
+ this->IntelProjectVersion = intelVersion;
}
return this->IntelProjectVersion;
}
@@ -190,11 +188,14 @@ const char* cmGlobalVisualStudio7Generator::ExternalProjectType(
}
return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942";
}
-void cmGlobalVisualStudio7Generator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& /*projectDir*/,
- const std::string& targetName, const std::string& config, bool /*fast*/,
- int /*jobs*/, bool /*verbose*/, std::vector<std::string> const& makeOptions)
+
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalVisualStudio7Generator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& /*projectDir*/,
+ std::vector<std::string> const& targetNames, const std::string& config,
+ bool /*fast*/, int /*jobs*/, bool /*verbose*/,
+ std::vector<std::string> const& makeOptions)
{
// Select the caller- or user-preferred make program, else devenv.
std::string makeProgramSelected =
@@ -210,27 +211,42 @@ void cmGlobalVisualStudio7Generator::GenerateBuildCommand(
}
// Workaround to convince VCExpress.exe to produce output.
- makeCommand.RequiresOutputForward =
+ const bool requiresOutputForward =
(makeProgramLower.find("vcexpress") != std::string::npos);
+ std::vector<GeneratedMakeCommand> makeCommands;
- makeCommand.add(makeProgramSelected);
-
- makeCommand.add(std::string(projectName) + ".sln");
- std::string realTarget = targetName;
- bool clean = false;
- if (realTarget == "clean") {
- clean = true;
- realTarget = "ALL_BUILD";
+ std::vector<std::string> realTargetNames = targetNames;
+ if (targetNames.empty() ||
+ ((targetNames.size() == 1) && targetNames.front().empty())) {
+ realTargetNames = { "ALL_BUILD" };
}
-
- makeCommand.add((clean ? "/clean" : "/build"));
- makeCommand.add((config.empty() ? "Debug" : config));
- makeCommand.add("/project");
- makeCommand.add((realTarget.empty() ? "ALL_BUILD" : realTarget));
- makeCommand.add(makeOptions.begin(), makeOptions.end());
+ for (const auto& tname : realTargetNames) {
+ std::string realTarget;
+ if (!tname.empty()) {
+ realTarget = tname;
+ } else {
+ continue;
+ }
+ bool clean = false;
+ if (realTarget == "clean") {
+ clean = true;
+ realTarget = "ALL_BUILD";
+ }
+ GeneratedMakeCommand makeCommand;
+ makeCommand.RequiresOutputForward = requiresOutputForward;
+ makeCommand.Add(makeProgramSelected);
+ makeCommand.Add(projectName + ".sln");
+ makeCommand.Add((clean ? "/clean" : "/build"));
+ makeCommand.Add((config.empty() ? "Debug" : config));
+ makeCommand.Add("/project");
+ makeCommand.Add(realTarget);
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ makeCommands.emplace_back(std::move(makeCommand));
+ }
+ return makeCommands;
}
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
cmLocalGenerator* cmGlobalVisualStudio7Generator::CreateLocalGenerator(
cmMakefile* mf)
{
@@ -252,7 +268,7 @@ bool cmGlobalVisualStudio7Generator::SetSystemName(std::string const& s,
cmMakefile* mf)
{
mf->AddDefinition("CMAKE_VS_INTEL_Fortran_PROJECT_VERSION",
- this->GetIntelProjectVersion());
+ this->GetIntelProjectVersion().c_str());
return this->cmGlobalVisualStudioGenerator::SetSystemName(s, mf);
}
@@ -597,7 +613,7 @@ std::string cmGlobalVisualStudio7Generator::GetGUID(std::string const& name)
{
std::string const& guidStoreName = name + "_GUID_CMAKE";
if (const char* storedGUID =
- this->CMakeInstance->GetCacheDefinition(guidStoreName.c_str())) {
+ this->CMakeInstance->GetCacheDefinition(guidStoreName)) {
return std::string(storedGUID);
}
// Compute a GUID that is deterministic but unique to the build tree.
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index 3f1c1732d..f004afb9c 100644
--- a/Source/cmGlobalVisualStudio7Generator.h
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -20,7 +20,7 @@ class cmGlobalVisualStudio7Generator : public cmGlobalVisualStudioGenerator
public:
~cmGlobalVisualStudio7Generator();
- ///! Create a local generator appropriate to this Global Generator
+ //! Create a local generator appropriate to this Global Generator
cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
#if defined(CMAKE_BUILD_WITH_CMAKE)
@@ -52,22 +52,19 @@ public:
* Try running cmake and building a file. This is used for dynamically
* loaded commands, not as part of the usual build process.
*/
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
/**
* Generate the DSW workspace file.
*/
virtual void OutputSLNFile();
- ///! Lookup a stored GUID or compute one deterministically.
+ //! Lookup a stored GUID or compute one deterministically.
std::string GetGUID(std::string const& name);
/** Append the subdirectory for the given configuration. */
@@ -76,7 +73,7 @@ public:
const std::string& suffix,
std::string& dir) override;
- ///! What is the configurations directory variable called?
+ //! What is the configurations directory variable called?
const char* GetCMakeCFGIntDir() const override
{
return "$(ConfigurationName)";
@@ -89,7 +86,7 @@ public:
return false;
}
- const char* GetIntelProjectVersion();
+ const std::string& GetIntelProjectVersion();
bool FindMakeProgram(cmMakefile* mf) override;
@@ -166,7 +163,7 @@ protected:
bool NasmEnabled;
private:
- char* IntelProjectVersion;
+ std::string IntelProjectVersion;
std::string DevEnvCommand;
bool DevEnvCommandInitialized;
std::string GetVSMakeProgram() override { return this->GetDevEnvCommand(); }
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
index f6db018ea..85ddc85b5 100644
--- a/Source/cmGlobalVisualStudio8Generator.cxx
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -141,10 +141,8 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
// Collect the input files used to generate all targets in this
// project.
std::vector<std::string> listFiles;
- for (unsigned int j = 0; j < generators.size(); ++j) {
- cmMakefile* lmf = generators[j]->GetMakefile();
- listFiles.insert(listFiles.end(), lmf->GetListFiles().begin(),
- lmf->GetListFiles().end());
+ for (cmLocalGenerator* gen : generators) {
+ cmAppend(listFiles, gen->GetMakefile()->GetListFiles());
}
// Add a custom prebuild target to run the VerifyGlobs script.
@@ -188,8 +186,8 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
commandLine.push_back("--check-stamp-list");
commandLine.push_back(stampList.c_str());
commandLine.push_back("--vs-solution-file");
- std::string const sln = std::string(lg->GetBinaryDirectory()) + "/" +
- lg->GetProjectName() + ".sln";
+ std::string const sln =
+ lg->GetBinaryDirectory() + "/" + lg->GetProjectName() + ".sln";
commandLine.push_back(sln);
cmCustomCommandLines commandLines;
commandLines.push_back(commandLine);
@@ -205,7 +203,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
"Checking Build System", no_working_directory, true, false)) {
gt->AddSource(file->GetFullPath());
} else {
- cmSystemTools::Error("Error adding rule for ", stamps[0].c_str());
+ cmSystemTools::Error("Error adding rule for " + stamps[0]);
}
}
@@ -273,7 +271,7 @@ void cmGlobalVisualStudio8Generator::WriteProjectConfigurations(
: this->GetPlatformName())
<< "\n";
}
- if (this->NeedsDeploy(target.GetType())) {
+ if (this->NeedsDeploy(target, dstConfig)) {
fout << "\t\t{" << guid << "}." << i << "|" << this->GetPlatformName()
<< ".Deploy.0 = " << dstConfig << "|"
<< (!platformMapping.empty() ? platformMapping
@@ -284,11 +282,32 @@ void cmGlobalVisualStudio8Generator::WriteProjectConfigurations(
}
bool cmGlobalVisualStudio8Generator::NeedsDeploy(
- cmStateEnums::TargetType type) const
+ cmGeneratorTarget const& target, const char* config) const
{
- bool needsDeploy =
- (type == cmStateEnums::EXECUTABLE || type == cmStateEnums::SHARED_LIBRARY);
- return this->TargetsWindowsCE() && needsDeploy;
+ cmStateEnums::TargetType type = target.GetType();
+ bool noDeploy = DeployInhibited(target, config);
+ return !noDeploy &&
+ (type == cmStateEnums::EXECUTABLE ||
+ type == cmStateEnums::SHARED_LIBRARY) &&
+ this->TargetSystemSupportsDeployment();
+}
+
+bool cmGlobalVisualStudio8Generator::DeployInhibited(
+ cmGeneratorTarget const& target, const char* config) const
+{
+ bool rVal = false;
+ if (const char* propStr = target.GetProperty("VS_NO_SOLUTION_DEPLOY")) {
+ cmGeneratorExpression ge;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(propStr);
+ std::string prop = cge->Evaluate(target.LocalGenerator, config);
+ rVal = cmSystemTools::IsOn(prop);
+ }
+ return rVal;
+}
+
+bool cmGlobalVisualStudio8Generator::TargetSystemSupportsDeployment() const
+{
+ return this->TargetsWindowsCE();
}
bool cmGlobalVisualStudio8Generator::ComputeTargetDepends()
diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h
index 8719bf3bb..352bc3c2b 100644
--- a/Source/cmGlobalVisualStudio8Generator.h
+++ b/Source/cmGlobalVisualStudio8Generator.h
@@ -13,7 +13,7 @@
class cmGlobalVisualStudio8Generator : public cmGlobalVisualStudio71Generator
{
public:
- ///! Get the name for the generator.
+ //! Get the name for the generator.
std::string GetName() const override { return this->Name; }
/** Get the name of the main stamp list file. */
@@ -54,7 +54,15 @@ protected:
bool AddCheckTarget();
/** Return true if the configuration needs to be deployed */
- virtual bool NeedsDeploy(cmStateEnums::TargetType type) const;
+ virtual bool NeedsDeploy(cmGeneratorTarget const& target,
+ const char* config) const;
+
+ /** Returns true if deployment has been disabled in cmake file. */
+ bool DeployInhibited(cmGeneratorTarget const& target,
+ const char* config) const;
+
+ /** Returns true if the target system support debugging deployment. */
+ virtual bool TargetSystemSupportsDeployment() const;
static cmIDEFlagTable const* GetExtraFlagTableVS8();
void WriteSolutionConfigurations(
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index cc5a88004..cd0355f6f 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -12,6 +12,7 @@
#include "cmAlgorithms.h"
#include "cmCallVisualStudioMacro.h"
+#include "cmCustomCommand.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmLocalVisualStudioGenerator.h"
@@ -202,14 +203,12 @@ void cmGlobalVisualStudioGenerator::AddExtraIDETargets()
// Now make all targets depend on the ALL_BUILD target
for (cmLocalGenerator const* i : gen) {
- std::vector<cmGeneratorTarget*> const& targets =
- i->GetGeneratorTargets();
- for (cmGeneratorTarget* tgt : targets) {
+ for (cmGeneratorTarget* tgt : i->GetGeneratorTargets()) {
if (tgt->GetType() == cmStateEnums::GLOBAL_TARGET ||
tgt->IsImported()) {
continue;
}
- if (!this->IsExcluded(gen[0], tgt)) {
+ if (!this->IsExcluded(tgt)) {
allBuild->AddUtility(tgt->GetName());
}
}
@@ -317,17 +316,7 @@ void cmGlobalVisualStudioGenerator::CallVisualStudioMacro(
std::vector<std::string> filenames;
this->GetFilesReplacedDuringGenerate(filenames);
if (!filenames.empty()) {
- // Convert vector to semi-colon delimited string of filenames:
- std::string projects;
- std::vector<std::string>::iterator it = filenames.begin();
- if (it != filenames.end()) {
- projects = *it;
- ++it;
- }
- for (; it != filenames.end(); ++it) {
- projects += ";";
- projects += *it;
- }
+ std::string projects = cmJoin(filenames, ";");
cmCallVisualStudioMacro::CallMacro(
topLevelSlnName, CMAKE_VSMACROS_RELOAD_MACRONAME, projects,
this->GetCMakeInstance()->GetDebugOutput());
@@ -367,7 +356,7 @@ void cmGlobalVisualStudioGenerator::FillLinkClosure(
cmGlobalVisualStudioGenerator::TargetSet const&
cmGlobalVisualStudioGenerator::GetTargetLinkClosure(cmGeneratorTarget* target)
{
- TargetSetMap::iterator i = this->TargetLinkClosure.find(target);
+ auto i = this->TargetLinkClosure.find(target);
if (i == this->TargetLinkClosure.end()) {
TargetSetMap::value_type entry(target, TargetSet());
i = this->TargetLinkClosure.insert(entry).first;
@@ -401,11 +390,8 @@ bool cmGlobalVisualStudioGenerator::ComputeTargetDepends()
return false;
}
for (auto const& it : this->ProjectMap) {
- std::vector<cmLocalGenerator*> const& gen = it.second;
- for (const cmLocalGenerator* i : gen) {
- std::vector<cmGeneratorTarget*> const& targets =
- i->GetGeneratorTargets();
- for (cmGeneratorTarget* ti : targets) {
+ for (const cmLocalGenerator* i : it.second) {
+ for (cmGeneratorTarget* ti : i->GetGeneratorTargets()) {
this->ComputeVSTargetDepends(ti);
}
}
@@ -457,8 +443,7 @@ void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(
std::set<cmGeneratorTarget const*> linkDepends;
if (target->GetType() != cmStateEnums::STATIC_LIBRARY) {
for (cmTargetDepend const& di : depends) {
- cmTargetDepend dep = di;
- if (dep.IsLink()) {
+ if (di.IsLink()) {
this->FollowLinkDepends(di, linkDepends);
}
}
@@ -467,8 +452,7 @@ void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(
// Collect explicit util dependencies (add_dependencies).
std::set<cmGeneratorTarget const*> utilDepends;
for (cmTargetDepend const& di : depends) {
- cmTargetDepend dep = di;
- if (dep.IsUtil()) {
+ if (di.IsUtil()) {
this->FollowLinkDepends(di, utilDepends);
}
}
@@ -512,7 +496,7 @@ bool cmGlobalVisualStudioGenerator::FindMakeProgram(cmMakefile* mf)
std::string cmGlobalVisualStudioGenerator::GetUtilityDepend(
cmGeneratorTarget const* target)
{
- UtilityDependsMap::iterator i = this->UtilityDepends.find(target);
+ auto i = this->UtilityDepends.find(target);
if (i == this->UtilityDepends.end()) {
std::string name = this->WriteUtilityDepend(target);
UtilityDependsMap::value_type entry(target, name);
@@ -930,7 +914,7 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand(
cmdl.push_back(objs_file);
cmGeneratedFileStream fout(objs_file.c_str());
if (!fout) {
- cmSystemTools::Error("could not open ", objs_file.c_str());
+ cmSystemTools::Error("could not open " + objs_file);
return;
}
@@ -938,11 +922,10 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand(
std::vector<std::string> objs;
for (cmSourceFile const* it : objectSources) {
// Find the object file name corresponding to this source file.
- std::map<cmSourceFile const*, std::string>::const_iterator map_it =
- mapping.find(it);
// It must exist because we populated the mapping just above.
- assert(!map_it->second.empty());
- std::string objFile = obj_dir + map_it->second;
+ const auto& v = mapping[it];
+ assert(!v.empty());
+ std::string objFile = obj_dir + v;
objs.push_back(objFile);
}
std::vector<cmSourceFile const*> externalObjectSources;
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
index f52abd0dc..2ba1affde 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
@@ -211,8 +211,8 @@ class cmGlobalVisualStudioVersionedGenerator::Factory16
: public cmGlobalGeneratorFactory
{
public:
- virtual cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
- cmake* cm) const
+ cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
+ cmake* cm) const override
{
std::string genName;
const char* p = cmVS16GenName(name, genName);
@@ -226,7 +226,7 @@ public:
return 0;
}
- virtual void GetDocumentation(cmDocumentationEntry& entry) const
+ void GetDocumentation(cmDocumentationEntry& entry) const override
{
entry.Name = std::string(vs16generatorName);
entry.Brief = "Generates Visual Studio 2019 project files. "
diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx
index c02c4711a..8a2738431 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.cxx
+++ b/Source/cmGlobalWatcomWMakeGenerator.cxx
@@ -3,6 +3,7 @@
#include "cmGlobalWatcomWMakeGenerator.h"
#include "cmDocumentationEntry.h"
+#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmState.h"
#include "cmake.h"
@@ -50,15 +51,16 @@ void cmGlobalWatcomWMakeGenerator::GetDocumentation(
entry.Brief = "Generates Watcom WMake makefiles.";
}
-void cmGlobalWatcomWMakeGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& projectDir,
- const std::string& targetName, const std::string& config, bool fast,
- int /*jobs*/, bool verbose, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalWatcomWMakeGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int /*jobs*/, bool verbose,
+ std::vector<std::string> const& makeOptions)
{
- this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
- makeCommand, makeProgram, projectName, projectDir, targetName, config,
- fast, cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
+ return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
+ makeProgram, projectName, projectDir, targetNames, config, fast,
+ cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
}
void cmGlobalWatcomWMakeGenerator::PrintBuildCommandAdvice(std::ostream& os,
diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h
index 6680b193f..3ca5e7d86 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.h
+++ b/Source/cmGlobalWatcomWMakeGenerator.h
@@ -29,7 +29,7 @@ public:
{
return new cmGlobalGeneratorSimpleFactory<cmGlobalWatcomWMakeGenerator>();
}
- ///! Get the name for the generator.
+ //! Get the name for the generator.
std::string GetName() const override
{
return cmGlobalWatcomWMakeGenerator::GetActualName();
@@ -50,15 +50,12 @@ public:
bool AllowDeleteOnError() const override { return false; }
protected:
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
};
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index dc63ce66b..7c2bcd386 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -12,6 +12,7 @@
#include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h"
+#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
#include "cmDocumentationEntry.h"
#include "cmGeneratedFileStream.h"
@@ -201,7 +202,7 @@ cmGlobalGenerator* cmGlobalXCodeGenerator::Factory::CreateGlobalGenerator(
}
}
}
- if (!versionFile.empty() && cmSystemTools::FileExists(versionFile.c_str())) {
+ if (!versionFile.empty() && cmSystemTools::FileExists(versionFile)) {
parser.ParseFile(versionFile.c_str());
} else if (cmSystemTools::FileExists(
"/Applications/Xcode.app/Contents/version.plist")) {
@@ -217,7 +218,7 @@ cmGlobalGenerator* cmGlobalXCodeGenerator::Factory::CreateGlobalGenerator(
sscanf(version_string.c_str(), "%u.%u", &v[0], &v[1]);
unsigned int version_number = 10 * v[0] + v[1];
- if (version_number < 30) {
+ if (version_number < 50) {
cm->IssueMessage(MessageType::FATAL_ERROR,
"Xcode " + version_string + " not supported.");
return nullptr;
@@ -256,15 +257,11 @@ std::string const& cmGlobalXCodeGenerator::GetXcodeBuildCommand()
std::string cmGlobalXCodeGenerator::FindXcodeBuildCommand()
{
- if (this->XcodeVersion >= 40) {
- std::string makeProgram = cmSystemTools::FindProgram("xcodebuild");
- if (makeProgram.empty()) {
- makeProgram = "xcodebuild";
- }
- return makeProgram;
+ std::string makeProgram = cmSystemTools::FindProgram("xcodebuild");
+ if (makeProgram.empty()) {
+ makeProgram = "xcodebuild";
}
- // Use cmakexbuild wrapper to suppress environment dump from output.
- return cmSystemTools::GetCMakeCommand() + "xbuild";
+ return makeProgram;
}
bool cmGlobalXCodeGenerator::SetGeneratorToolset(std::string const& ts,
@@ -338,49 +335,61 @@ bool cmGlobalXCodeGenerator::Open(const std::string& bindir,
return ret;
}
-void cmGlobalXCodeGenerator::GenerateBuildCommand(
- GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
- const std::string& projectName, const std::string& /*projectDir*/,
- const std::string& targetName, const std::string& config, bool /*fast*/,
- int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
+std::vector<cmGlobalGenerator::GeneratedMakeCommand>
+cmGlobalXCodeGenerator::GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& /*projectDir*/,
+ std::vector<std::string> const& targetNames, const std::string& config,
+ bool /*fast*/, int jobs, bool /*verbose*/,
+ std::vector<std::string> const& makeOptions)
{
+ GeneratedMakeCommand makeCommand;
// now build the test
- makeCommand.add(
+ makeCommand.Add(
this->SelectMakeProgram(makeProgram, this->GetXcodeBuildCommand()));
if (!projectName.empty()) {
- makeCommand.add("-project");
+ makeCommand.Add("-project");
std::string projectArg = projectName;
projectArg += ".xcode";
projectArg += "proj";
- makeCommand.add(projectArg);
+ makeCommand.Add(projectArg);
}
-
- bool clean = false;
- std::string realTarget = targetName;
- if (realTarget == "clean") {
- clean = true;
- realTarget = "ALL_BUILD";
+ if (std::find(targetNames.begin(), targetNames.end(), "clean") !=
+ targetNames.end()) {
+ makeCommand.Add("clean");
+ makeCommand.Add("-target", "ALL_BUILD");
+ } else {
+ makeCommand.Add("build");
+ if (targetNames.empty() ||
+ ((targetNames.size() == 1) && targetNames.front().empty())) {
+ makeCommand.Add("-target", "ALL_BUILD");
+ } else {
+ for (const auto& tname : targetNames) {
+ if (!tname.empty()) {
+ makeCommand.Add("-target", tname);
+ }
+ }
+ }
}
- makeCommand.add((clean ? "clean" : "build"));
- makeCommand.add("-target", (realTarget.empty() ? "ALL_BUILD" : realTarget));
- makeCommand.add("-configuration", (config.empty() ? "Debug" : config));
+ makeCommand.Add("-configuration", (config.empty() ? "Debug" : config));
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
- makeCommand.add("-jobs");
+ makeCommand.Add("-jobs");
if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
- makeCommand.add(std::to_string(jobs));
+ makeCommand.Add(std::to_string(jobs));
}
}
if (this->XcodeVersion >= 70) {
- makeCommand.add("-hideShellScriptEnvironment");
+ makeCommand.Add("-hideShellScriptEnvironment");
}
- makeCommand.add(makeOptions.begin(), makeOptions.end());
+ makeCommand.Add(makeOptions.begin(), makeOptions.end());
+ return { std::move(makeCommand) };
}
-///! Create a local generator appropriate to this Global Generator
+//! Create a local generator appropriate to this Global Generator
cmLocalGenerator* cmGlobalXCodeGenerator::CreateLocalGenerator(cmMakefile* mf)
{
return new cmLocalXCodeGenerator(this, mf);
@@ -470,7 +479,7 @@ void cmGlobalXCodeGenerator::SetGenerationRoot(cmLocalGenerator* root)
this->CurrentXCodeHackMakefile = root->GetCurrentBinaryDirectory();
this->CurrentXCodeHackMakefile += "/CMakeScripts";
- cmSystemTools::MakeDirectory(this->CurrentXCodeHackMakefile.c_str());
+ cmSystemTools::MakeDirectory(this->CurrentXCodeHackMakefile);
this->CurrentXCodeHackMakefile += "/XCODE_DEPEND_HELPER.make";
}
@@ -550,12 +559,7 @@ void cmGlobalXCodeGenerator::AddExtraTargets(
// run the depend check makefile as a post build rule
// this will make sure that when the next target is built
// things are up-to-date
- if (target->GetType() == cmStateEnums::OBJECT_LIBRARY ||
- (this->XcodeVersion < 50 &&
- (target->GetType() == cmStateEnums::EXECUTABLE ||
- target->GetType() == cmStateEnums::STATIC_LIBRARY ||
- target->GetType() == cmStateEnums::SHARED_LIBRARY ||
- target->GetType() == cmStateEnums::MODULE_LIBRARY))) {
+ if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
makeHelper.back() = // fill placeholder
this->PostBuildMakeTarget(target->GetName(), "$(CONFIGURATION)");
cmCustomCommandLines commandLines;
@@ -564,10 +568,10 @@ void cmGlobalXCodeGenerator::AddExtraTargets(
gen->GetMakefile()->AddCustomCommandToTarget(
target->GetName(), no_byproducts, no_depends, commandLines,
cmTarget::POST_BUILD, "Depend check for xcode", dir.c_str(), true,
- false, "", false, cmMakefile::AcceptObjectLibraryCommands);
+ false, "", "", false, cmMakefile::AcceptObjectLibraryCommands);
}
- if (!this->IsExcluded(gens[0], target)) {
+ if (!this->IsExcluded(target)) {
allbuild->AddUtility(target->GetName());
}
}
@@ -579,8 +583,7 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile(
{
std::vector<std::string> lfiles;
for (auto gen : gens) {
- std::vector<std::string> const& lf = gen->GetMakefile()->GetListFiles();
- lfiles.insert(lfiles.end(), lf.begin(), lf.end());
+ cmAppend(lfiles, gen->GetMakefile()->GetListFiles());
}
// sort the array
@@ -596,7 +599,7 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile(
this->CurrentReRunCMakeMakefile = root->GetCurrentBinaryDirectory();
this->CurrentReRunCMakeMakefile += "/CMakeScripts";
- cmSystemTools::MakeDirectory(this->CurrentReRunCMakeMakefile.c_str());
+ cmSystemTools::MakeDirectory(this->CurrentReRunCMakeMakefile);
this->CurrentReRunCMakeMakefile += "/ReRunCMake.make";
cmGeneratedFileStream makefileStream(this->CurrentReRunCMakeMakefile);
makefileStream.SetCopyIfDifferent(true);
@@ -1019,11 +1022,10 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
this->CreateString(fileType));
// Store the file path relative to the top of the source tree.
- std::string path = this->RelativeToSource(fullpath.c_str());
+ std::string path = this->RelativeToSource(fullpath);
std::string name = cmSystemTools::GetFilenameName(path);
const char* sourceTree =
- (cmSystemTools::FileIsFullPath(path.c_str()) ? "<absolute>"
- : "SOURCE_ROOT");
+ cmSystemTools::FileIsFullPath(path) ? "<absolute>" : "SOURCE_ROOT";
fileRef->AddAttribute("name", this->CreateString(name));
fileRef->AddAttribute("path", this->CreateString(path));
fileRef->AddAttribute("sourceTree", this->CreateString(sourceTree));
@@ -1190,23 +1192,6 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget(
}
}
- if (this->XcodeVersion < 50) {
- // Add object library contents as external objects. (Equivalent to
- // the externalObjFiles above, except each one is not a cmSourceFile
- // within the target.)
- std::vector<cmSourceFile const*> objs;
- gtgt->GetExternalObjects(objs, "");
- for (auto sourceFile : objs) {
- if (sourceFile->GetObjectLibrary().empty()) {
- continue;
- }
- std::string const& obj = sourceFile->GetFullPath();
- cmXCodeObject* xsf =
- this->CreateXCodeSourceFileFromPath(obj, gtgt, "", nullptr);
- externalObjFiles.push_back(xsf);
- }
- }
-
// some build phases only apply to bundles and/or frameworks
bool isFrameworkTarget = gtgt->IsFrameworkOnApple();
bool isBundleTarget = gtgt->GetPropertyAsBool("MACOSX_BUNDLE");
@@ -1601,7 +1586,7 @@ std::string cmGlobalXCodeGenerator::ExtractFlagRegex(const char* exp,
std::string::size_type offset = 0;
- while (regex.find(flags.c_str() + offset)) {
+ while (regex.find(&flags[offset])) {
const std::string::size_type startPos = offset + regex.start(matchIndex);
const std::string::size_type endPos = offset + regex.end(matchIndex);
const std::string::size_type size = endPos - startPos;
@@ -1654,7 +1639,7 @@ void cmGlobalXCodeGenerator::AddCommandsToBuildPhase(
{
std::string dir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory();
dir += "/CMakeScripts";
- cmSystemTools::MakeDirectory(dir.c_str());
+ cmSystemTools::MakeDirectory(dir);
std::string makefile = dir;
makefile += "/";
makefile += target->GetName();
@@ -1713,7 +1698,7 @@ void cmGlobalXCodeGenerator::CreateCustomRulesMakefile(
} else {
std::ostringstream str;
str << "_buildpart_" << count++;
- tname[&ccg.GetCC()] = std::string(target->GetName()) + str.str();
+ tname[&ccg.GetCC()] = target->GetName() + str.str();
makefileStream << "\\\n\t" << tname[&ccg.GetCC()];
}
}
@@ -1820,6 +1805,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
this->CurrentLocalGenerator->AddLanguageFlags(flags, gtgt, lang,
configName);
+ if (gtgt->IsIPOEnabled(lang, configName)) {
+ this->CurrentLocalGenerator->AppendFeatureOptions(flags, lang, "IPO");
+ }
+
// Add shared-library flags if needed.
this->CurrentLocalGenerator->AddCMP0018Flags(flags, gtgt, lang,
configName);
@@ -1833,8 +1822,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
std::string llang = gtgt->GetLinkerLanguage(configName);
if (binary && llang.empty()) {
cmSystemTools::Error(
- "CMake can not determine linker language for target: ",
- gtgt->GetName().c_str());
+ "CMake can not determine linker language for target: " +
+ gtgt->GetName());
return;
}
std::string const& langForPreprocessor = llang;
@@ -2009,7 +1998,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
// so let it replace the framework name. This avoids creating
// a per-configuration Info.plist file.
this->CurrentLocalGenerator->GenerateFrameworkInfoPList(
- gtgt, "$(EXECUTABLE_NAME)", plist.c_str());
+ gtgt, "$(EXECUTABLE_NAME)", plist);
buildSettings->AddAttribute("INFOPLIST_FILE",
this->CreateString(plist));
buildSettings->AddAttribute("MACH_O_TYPE",
@@ -2050,7 +2039,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
// a per-configuration Info.plist file. The cfbundle plist
// is very similar to the application bundle plist
this->CurrentLocalGenerator->GenerateAppleInfoPList(
- gtgt, "$(EXECUTABLE_NAME)", plist.c_str());
+ gtgt, "$(EXECUTABLE_NAME)", plist);
buildSettings->AddAttribute("INFOPLIST_FILE",
this->CreateString(plist));
} else {
@@ -2084,7 +2073,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
// so let it replace the framework name. This avoids creating
// a per-configuration Info.plist file.
this->CurrentLocalGenerator->GenerateFrameworkInfoPList(
- gtgt, "$(EXECUTABLE_NAME)", plist.c_str());
+ gtgt, "$(EXECUTABLE_NAME)", plist);
buildSettings->AddAttribute("INFOPLIST_FILE",
this->CreateString(plist));
} else {
@@ -2122,7 +2111,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
// so let it replace the executable name. This avoids creating
// a per-configuration Info.plist file.
this->CurrentLocalGenerator->GenerateAppleInfoPList(
- gtgt, "$(EXECUTABLE_NAME)", plist.c_str());
+ gtgt, "$(EXECUTABLE_NAME)", plist);
buildSettings->AddAttribute("INFOPLIST_FILE",
this->CreateString(plist));
}
@@ -2130,9 +2119,6 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
default:
break;
}
- if (this->XcodeVersion < 40) {
- buildSettings->AddAttribute("PREBINDING", this->CreateString("NO"));
- }
BuildObjectListOrString dirs(this, true);
BuildObjectListOrString fdirs(this, true);
@@ -2497,12 +2483,10 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateUtilityTarget(
std::string cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target,
cmGeneratorTarget* gtgt)
{
- std::string configTypes =
- this->CurrentMakefile->GetRequiredDefinition("CMAKE_CONFIGURATION_TYPES");
- std::vector<std::string> configVectorIn;
- std::vector<std::string> configVector;
- configVectorIn.push_back(configTypes);
- cmSystemTools::ExpandList(configVectorIn, configVector);
+ std::vector<std::string> const configVector =
+ cmSystemTools::ExpandedListArgument(
+ this->CurrentMakefile->GetRequiredDefinition(
+ "CMAKE_CONFIGURATION_TYPES"));
cmXCodeObject* configlist =
this->CreateObject(cmXCodeObject::XCConfigurationList);
cmXCodeObject* buildConfigurations =
@@ -2782,8 +2766,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
// Loop over configuration types and set per-configuration info.
for (auto const& configName : this->CurrentConfigurationTypes) {
- // Get the current configuration name.
- if (this->XcodeVersion >= 50) {
+ {
// Add object library contents as link flags.
std::string linkObjs;
const char* sep = "";
@@ -2893,7 +2876,7 @@ bool cmGlobalXCodeGenerator::CreateGroups(
// Put cmSourceFile instances in proper groups:
for (auto const& si : gtgt->GetAllConfigSources()) {
cmSourceFile const* sf = si.Source;
- if (this->XcodeVersion >= 50 && !sf->GetObjectLibrary().empty()) {
+ if (!sf->GetObjectLibrary().empty()) {
// Object library files go on the link line instead.
continue;
}
@@ -3029,10 +3012,11 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
- for (auto& CurrentConfigurationType : this->CurrentConfigurationTypes) {
+ for (const std::string& CurrentConfigurationType :
+ this->CurrentConfigurationTypes) {
cmXCodeObject* buildStyle =
this->CreateObject(cmXCodeObject::PBXBuildStyle);
- const char* name = CurrentConfigurationType.c_str();
+ const std::string& name = CurrentConfigurationType;
buildStyle->AddAttribute("name", this->CreateString(name));
buildStyle->SetComment(name);
cmXCodeObject* sgroup = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
@@ -3081,20 +3065,12 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
v << std::setfill('0') << std::setw(4) << XcodeVersion * 10;
group->AddAttribute("LastUpgradeCheck", this->CreateString(v.str()));
this->RootObject->AddAttribute("attributes", group);
- if (this->XcodeVersion >= 32) {
- this->RootObject->AddAttribute("compatibilityVersion",
- this->CreateString("Xcode 3.2"));
- } else if (this->XcodeVersion >= 31) {
- this->RootObject->AddAttribute("compatibilityVersion",
- this->CreateString("Xcode 3.1"));
- } else {
- this->RootObject->AddAttribute("compatibilityVersion",
- this->CreateString("Xcode 3.0"));
- }
+ this->RootObject->AddAttribute("compatibilityVersion",
+ this->CreateString("Xcode 3.2"));
// Point Xcode at the top of the source tree.
{
std::string pdir =
- this->RelativeToBinary(root->GetCurrentSourceDirectory().c_str());
+ this->RelativeToBinary(root->GetCurrentSourceDirectory());
this->RootObject->AddAttribute("projectDirPath", this->CreateString(pdir));
this->RootObject->AddAttribute("projectRoot", this->CreateString(""));
}
@@ -3286,8 +3262,7 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
{
cmGeneratedFileStream makefileStream(this->CurrentXCodeHackMakefile);
if (!makefileStream) {
- cmSystemTools::Error("Could not create",
- this->CurrentXCodeHackMakefile.c_str());
+ cmSystemTools::Error("Could not create " + this->CurrentXCodeHackMakefile);
return;
}
makefileStream.SetCopyIfDifferent(true);
@@ -3424,7 +3399,7 @@ void cmGlobalXCodeGenerator::OutputXCodeProject(
xcodeDir += "/";
xcodeDir += root->GetProjectName();
xcodeDir += ".xcodeproj";
- cmSystemTools::MakeDirectory(xcodeDir.c_str());
+ cmSystemTools::MakeDirectory(xcodeDir);
std::string xcodeProjFile = xcodeDir + "/project.pbxproj";
cmGeneratedFileStream fout(xcodeProjFile);
fout.SetCopyIfDifferent(true);
@@ -3433,10 +3408,8 @@ void cmGlobalXCodeGenerator::OutputXCodeProject(
}
this->WriteXCodePBXProj(fout, root, generators);
- if (this->IsGeneratingScheme(root)) {
- this->OutputXCodeSharedSchemes(xcodeDir);
- }
- this->OutputXCodeWorkspaceSettings(xcodeDir, root);
+ bool hasGeneratedSchemes = this->OutputXCodeSharedSchemes(xcodeDir, root);
+ this->OutputXCodeWorkspaceSettings(xcodeDir, hasGeneratedSchemes);
this->ClearXCodeObjects();
@@ -3446,17 +3419,8 @@ void cmGlobalXCodeGenerator::OutputXCodeProject(
root->GetBinaryDirectory());
}
-bool cmGlobalXCodeGenerator::IsGeneratingScheme(cmLocalGenerator* root) const
-{
- // Since the lowest available Xcode version for testing was 6.4,
- // I'm setting this as a limit then
- return this->XcodeVersion >= 64 &&
- (root->GetMakefile()->GetCMakeInstance()->GetIsInTryCompile() ||
- root->GetMakefile()->IsOn("CMAKE_XCODE_GENERATE_SCHEME"));
-}
-
-void cmGlobalXCodeGenerator::OutputXCodeSharedSchemes(
- const std::string& xcProjDir)
+bool cmGlobalXCodeGenerator::OutputXCodeSharedSchemes(
+ const std::string& xcProjDir, cmLocalGenerator* root)
{
// collect all tests for the targets
std::map<std::string, cmXCodeScheme::TestObjects> testables;
@@ -3480,21 +3444,33 @@ void cmGlobalXCodeGenerator::OutputXCodeSharedSchemes(
}
// generate scheme
- for (auto obj : this->XCodeObjects) {
- if (obj->GetType() == cmXCodeObject::OBJECT &&
- (obj->GetIsA() == cmXCodeObject::PBXNativeTarget ||
- obj->GetIsA() == cmXCodeObject::PBXAggregateTarget)) {
- const std::string& targetName = obj->GetTarget()->GetName();
- cmXCodeScheme schm(obj, testables[targetName],
- this->CurrentConfigurationTypes, this->XcodeVersion);
- schm.WriteXCodeSharedScheme(xcProjDir,
- this->RelativeToSource(xcProjDir.c_str()));
+ bool ret = false;
+
+ // Since the lowest available Xcode version for testing was 6.4,
+ // I'm setting this as a limit then
+ if (this->XcodeVersion >= 64) {
+ for (auto obj : this->XCodeObjects) {
+ if (obj->GetType() == cmXCodeObject::OBJECT &&
+ (obj->GetIsA() == cmXCodeObject::PBXNativeTarget ||
+ obj->GetIsA() == cmXCodeObject::PBXAggregateTarget) &&
+ (root->GetMakefile()->GetCMakeInstance()->GetIsInTryCompile() ||
+ obj->GetTarget()->GetPropertyAsBool("XCODE_GENERATE_SCHEME"))) {
+ const std::string& targetName = obj->GetTarget()->GetName();
+ cmXCodeScheme schm(obj, testables[targetName],
+ this->CurrentConfigurationTypes,
+ this->XcodeVersion);
+ schm.WriteXCodeSharedScheme(xcProjDir,
+ this->RelativeToSource(xcProjDir));
+ ret = true;
+ }
}
}
+
+ return ret;
}
void cmGlobalXCodeGenerator::OutputXCodeWorkspaceSettings(
- const std::string& xcProjDir, cmLocalGenerator* root)
+ const std::string& xcProjDir, bool hasGeneratedSchemes)
{
std::string xcodeSharedDataDir = xcProjDir;
xcodeSharedDataDir += "/project.xcworkspace/xcshareddata";
@@ -3520,7 +3496,7 @@ void cmGlobalXCodeGenerator::OutputXCodeWorkspaceSettings(
xout.Element("key", "BuildSystemType");
xout.Element("string", "Original");
}
- if (this->IsGeneratingScheme(root)) {
+ if (hasGeneratedSchemes) {
xout.Element("key",
"IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded");
xout.Element("false");
@@ -3545,13 +3521,7 @@ void cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
cmXCodeObject::Indent(1, fout);
fout << "};\n";
cmXCodeObject::Indent(1, fout);
- if (this->XcodeVersion >= 32) {
- fout << "objectVersion = 46;\n";
- } else if (this->XcodeVersion >= 31) {
- fout << "objectVersion = 45;\n";
- } else {
- fout << "objectVersion = 44;\n";
- }
+ fout << "objectVersion = 46;\n";
cmXCode21Object::PrintList(this->XCodeObjects, fout);
cmXCodeObject::Indent(1, fout);
fout << "rootObject = " << this->RootObject->GetId()
@@ -3596,7 +3566,7 @@ std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake(
return cmSystemTools::ConvertToOutputPath(p);
}
-std::string cmGlobalXCodeGenerator::RelativeToSource(const char* p)
+std::string cmGlobalXCodeGenerator::RelativeToSource(const std::string& p)
{
// We force conversion because Xcode breakpoints do not work unless
// they are in a file named relative to the source tree.
@@ -3604,7 +3574,7 @@ std::string cmGlobalXCodeGenerator::RelativeToSource(const char* p)
cmSystemTools::JoinPath(this->ProjectSourceDirectoryComponents), p);
}
-std::string cmGlobalXCodeGenerator::RelativeToBinary(const char* p)
+std::string cmGlobalXCodeGenerator::RelativeToBinary(const std::string& p)
{
return this->CurrentLocalGenerator->MaybeConvertToRelativePath(
cmSystemTools::JoinPath(this->ProjectOutputDirectoryComponents), p);
@@ -3719,11 +3689,7 @@ void cmGlobalXCodeGenerator::AppendFlag(std::string& flags,
// Flag value with escaped quotes and backslashes.
for (auto c : flag) {
if (c == '\'') {
- if (this->XcodeVersion >= 40) {
- flags += "'\\''";
- } else {
- flags += "\\'";
- }
+ flags += "'\\''";
} else if (c == '\\') {
flags += "\\\\";
} else {
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index e1e412dca..71446f997 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -36,7 +36,7 @@ public:
unsigned int version_number);
static cmGlobalGeneratorFactory* NewFactory();
- ///! Get the name for the generator.
+ //! Get the name for the generator.
std::string GetName() const override
{
return cmGlobalXCodeGenerator::GetActualName();
@@ -46,7 +46,7 @@ public:
/** Get the documentation entry for this generator. */
static void GetDocumentation(cmDocumentationEntry& entry);
- ///! Create a local generator appropriate to this Global Generator
+ //! Create a local generator appropriate to this Global Generator
cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
/**
@@ -66,15 +66,12 @@ public:
* Try running cmake and building a file. This is used for dynalically
* loaded commands, not as part of the usual build process.
*/
- void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
- const std::string& makeProgram,
- const std::string& projectName,
- const std::string& projectDir,
- const std::string& targetName,
- const std::string& config, bool fast, int jobs,
- bool verbose,
- std::vector<std::string> const& makeOptions =
- std::vector<std::string>()) override;
+ std::vector<GeneratedMakeCommand> GenerateBuildCommand(
+ const std::string& makeProgram, const std::string& projectName,
+ const std::string& projectDir, std::vector<std::string> const& targetNames,
+ const std::string& config, bool fast, int jobs, bool verbose,
+ std::vector<std::string> const& makeOptions =
+ std::vector<std::string>()) override;
/** Append the subdirectory for the given configuration. */
void AppendDirectoryForConfig(const std::string& prefix,
@@ -84,9 +81,9 @@ public:
bool FindMakeProgram(cmMakefile*) override;
- ///! What is the configurations directory variable called?
+ //! What is the configurations directory variable called?
const char* GetCMakeCFGIntDir() const override;
- ///! expand CFGIntDir
+ //! expand CFGIntDir
std::string ExpandCFGIntDir(const std::string& str,
const std::string& config) const override;
@@ -122,8 +119,8 @@ private:
const std::string& name);
bool CreateGroups(std::vector<cmLocalGenerator*>& generators);
std::string XCodeEscapePath(const std::string& p);
- std::string RelativeToSource(const char* p);
- std::string RelativeToBinary(const char* p);
+ std::string RelativeToSource(const std::string& p);
+ std::string RelativeToBinary(const std::string& p);
std::string ConvertToRelativeForMake(std::string const& p);
void CreateCustomCommands(cmXCodeObject* buildPhases,
cmXCodeObject* sourceBuildPhase,
@@ -189,11 +186,12 @@ private:
std::vector<cmLocalGenerator*>& generators);
void OutputXCodeProject(cmLocalGenerator* root,
std::vector<cmLocalGenerator*>& generators);
- bool IsGeneratingScheme(cmLocalGenerator* root) const;
// Write shared scheme files for all the native targets
- void OutputXCodeSharedSchemes(const std::string& xcProjDir);
+ // return true if any were written
+ bool OutputXCodeSharedSchemes(const std::string& xcProjDir,
+ cmLocalGenerator* root);
void OutputXCodeWorkspaceSettings(const std::string& xcProjDir,
- cmLocalGenerator* root);
+ bool hasGeneratedSchemes);
void WriteXCodePBXProj(std::ostream& fout, cmLocalGenerator* root,
std::vector<cmLocalGenerator*>& generators);
cmXCodeObject* CreateXCodeFileReferenceFromPath(const std::string& fullpath,
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index 4b6027995..a75d8a97a 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -170,8 +170,9 @@ cmGraphVizWriter::cmGraphVizWriter(const cmGlobalGenerator* globalGenerator)
{
}
-void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
- const char* fallbackSettingsFileName)
+void cmGraphVizWriter::ReadSettings(
+ const std::string& settingsFileName,
+ const std::string& fallbackSettingsFileName)
{
cmake cm(cmake::RoleScript, cmState::Unknown);
cm.SetHomeDirectory("");
@@ -181,8 +182,7 @@ void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
cmMakefile mf(&ggi, cm.GetCurrentSnapshot());
std::unique_ptr<cmLocalGenerator> lg(ggi.CreateLocalGenerator(&mf));
- const char* inFileName = settingsFileName;
-
+ std::string inFileName = settingsFileName;
if (!cmSystemTools::FileExists(inFileName)) {
inFileName = fallbackSettingsFileName;
if (!cmSystemTools::FileExists(inFileName)) {
@@ -191,7 +191,7 @@ void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
}
if (!mf.ReadListFile(inFileName)) {
- cmSystemTools::Error("Problem opening GraphViz options file: ",
+ cmSystemTools::Error("Problem opening GraphViz options file: " +
inFileName);
return;
}
@@ -249,7 +249,7 @@ void cmGraphVizWriter::ReadSettings(const char* settingsFileName,
// Iterate over all targets and write for each one a graph which shows
// which other targets depend on it.
-void cmGraphVizWriter::WriteTargetDependersFiles(const char* fileName)
+void cmGraphVizWriter::WriteTargetDependersFiles(const std::string& fileName)
{
if (!this->GenerateDependers) {
return;
@@ -291,7 +291,7 @@ void cmGraphVizWriter::WriteTargetDependersFiles(const char* fileName)
// Iterate over all targets and write for each one a graph which shows
// on which targets it depends.
-void cmGraphVizWriter::WritePerTargetFiles(const char* fileName)
+void cmGraphVizWriter::WritePerTargetFiles(const std::string& fileName)
{
if (!this->GeneratePerTarget) {
return;
@@ -327,7 +327,7 @@ void cmGraphVizWriter::WritePerTargetFiles(const char* fileName)
}
}
-void cmGraphVizWriter::WriteGlobalFile(const char* fileName)
+void cmGraphVizWriter::WriteGlobalFile(const std::string& fileName)
{
this->CollectTargetsAndLibs();
@@ -392,7 +392,7 @@ void cmGraphVizWriter::WriteConnections(
GlobalGenerator);
for (auto const& llit : ll) {
- const char* libName = llit.first.c_str();
+ const std::string& libName = llit.first;
std::map<std::string, std::string>::const_iterator libNameIt =
this->TargetNamesNodes.find(libName);
@@ -519,7 +519,7 @@ int cmGraphVizWriter::CollectAllTargets()
for (cmLocalGenerator* lg : this->LocalGenerators) {
const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
for (cmGeneratorTarget* target : targets) {
- const char* realTargetName = target->GetName().c_str();
+ const std::string& realTargetName = target->GetName();
if (this->IgnoreThisTarget(realTargetName)) {
// Skip ignored targets
continue;
@@ -541,7 +541,7 @@ int cmGraphVizWriter::CollectAllExternalLibs(int cnt)
for (cmLocalGenerator* lg : this->LocalGenerators) {
const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
for (cmGeneratorTarget* target : targets) {
- const char* realTargetName = target->GetName().c_str();
+ const std::string& realTargetName = target->GetName();
if (this->IgnoreThisTarget(realTargetName)) {
// Skip ignored targets
continue;
@@ -549,7 +549,7 @@ int cmGraphVizWriter::CollectAllExternalLibs(int cnt)
const cmTarget::LinkLibraryVectorType* ll =
&(target->Target->GetOriginalLinkLibraries());
for (auto const& llit : *ll) {
- const char* libName = llit.first.c_str();
+ std::string libName = llit.first;
if (this->IgnoreThisTarget(libName)) {
// Skip ignored targets
continue;
@@ -558,7 +558,7 @@ int cmGraphVizWriter::CollectAllExternalLibs(int cnt)
if (GlobalGenerator->IsAlias(libName)) {
const auto tgt = GlobalGenerator->FindTarget(libName);
if (tgt) {
- libName = tgt->GetName().c_str();
+ libName = tgt->GetName();
}
}
diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h
index ed242f0ab..768683a3b 100644
--- a/Source/cmGraphVizWriter.h
+++ b/Source/cmGraphVizWriter.h
@@ -25,13 +25,13 @@ class cmGraphVizWriter
public:
cmGraphVizWriter(const cmGlobalGenerator* globalGenerator);
- void ReadSettings(const char* settingsFileName,
- const char* fallbackSettingsFileName);
+ void ReadSettings(const std::string& settingsFileName,
+ const std::string& fallbackSettingsFileName);
- void WritePerTargetFiles(const char* fileName);
- void WriteTargetDependersFiles(const char* fileName);
+ void WritePerTargetFiles(const std::string& fileName);
+ void WriteTargetDependersFiles(const std::string& fileName);
- void WriteGlobalFile(const char* fileName);
+ void WriteGlobalFile(const std::string& fileName);
protected:
void CollectTargetsAndLibs();
diff --git a/Source/cmHexFileConverter.cxx b/Source/cmHexFileConverter.cxx
index 4e29f399a..190f2e305 100644
--- a/Source/cmHexFileConverter.cxx
+++ b/Source/cmHexFileConverter.cxx
@@ -128,7 +128,7 @@ static bool ConvertIntelHexLine(const char* buf, FILE* outFile)
}
cmHexFileConverter::FileType cmHexFileConverter::DetermineFileType(
- const char* inFileName)
+ const std::string& inFileName)
{
char buf[1024];
FILE* inFile = cmsys::SystemTools::Fopen(inFileName, "rb");
@@ -170,8 +170,8 @@ cmHexFileConverter::FileType cmHexFileConverter::DetermineFileType(
return type;
}
-bool cmHexFileConverter::TryConvert(const char* inFileName,
- const char* outFileName)
+bool cmHexFileConverter::TryConvert(const std::string& inFileName,
+ const std::string& outFileName)
{
FileType type = DetermineFileType(inFileName);
if (type == Binary) {
diff --git a/Source/cmHexFileConverter.h b/Source/cmHexFileConverter.h
index 25278e4a3..cb5de8f34 100644
--- a/Source/cmHexFileConverter.h
+++ b/Source/cmHexFileConverter.h
@@ -4,6 +4,7 @@
#define cmHexFileConverter_h
#include "cmConfigure.h" // IWYU pragma: keep
+#include <string>
/** \class cmHexFileConverter
* \brief Can detects Intel Hex and Motorola S-record files and convert them
@@ -19,8 +20,9 @@ public:
IntelHex,
MotorolaSrec
};
- static FileType DetermineFileType(const char* inFileName);
- static bool TryConvert(const char* inFileName, const char* outFileName);
+ static FileType DetermineFileType(const std::string& inFileName);
+ static bool TryConvert(const std::string& inFileName,
+ const std::string& outFileName);
};
#endif
diff --git a/Source/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx
index ea67d45fa..7b992d743 100644
--- a/Source/cmIDEOptions.cxx
+++ b/Source/cmIDEOptions.cxx
@@ -6,6 +6,7 @@
#include <iterator>
#include <string.h>
+#include "cmAlgorithms.h"
#include "cmIDEFlagTable.h"
#include "cmSystemTools.h"
@@ -170,7 +171,7 @@ void cmIDEOptions::AddDefines(std::string const& defines)
}
void cmIDEOptions::AddDefines(const std::vector<std::string>& defines)
{
- this->Defines.insert(this->Defines.end(), defines.begin(), defines.end());
+ cmAppend(this->Defines, defines);
}
std::vector<std::string> const& cmIDEOptions::GetDefines() const
@@ -192,8 +193,7 @@ void cmIDEOptions::AddIncludes(std::string const& includes)
}
void cmIDEOptions::AddIncludes(const std::vector<std::string>& includes)
{
- this->Includes.insert(this->Includes.end(), includes.begin(),
- includes.end());
+ cmAppend(this->Includes, includes);
}
std::vector<std::string> const& cmIDEOptions::GetIncludes() const
diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx
index 549a263e3..62e2abdcd 100644
--- a/Source/cmIncludeDirectoryCommand.cxx
+++ b/Source/cmIncludeDirectoryCommand.cxx
@@ -6,6 +6,7 @@
#include <set>
#include <utility>
+#include "cmAlgorithms.h"
#include "cmGeneratorExpression.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
@@ -52,11 +53,9 @@ bool cmIncludeDirectoryCommand::InitialPass(
this->GetIncludes(*i, includes);
if (before) {
- beforeIncludes.insert(beforeIncludes.end(), includes.begin(),
- includes.end());
+ cmAppend(beforeIncludes, includes);
} else {
- afterIncludes.insert(afterIncludes.end(), includes.begin(),
- includes.end());
+ cmAppend(afterIncludes, includes);
}
if (system) {
systemIncludes.insert(includes.begin(), includes.end());
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 20d1a3134..dba4bbb30 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmInstallCommand.h"
+#include "cm_static_string_view.hxx"
#include "cmsys/Glob.hxx"
#include <set>
#include <sstream>
@@ -9,7 +10,7 @@
#include <utility>
#include "cmAlgorithms.h"
-#include "cmCommandArgumentsHelper.h"
+#include "cmArgumentParser.h"
#include "cmExportSet.h"
#include "cmExportSetMap.h"
#include "cmGeneratorExpression.h"
@@ -219,49 +220,51 @@ bool cmInstallCommand::HandleScriptMode(std::vector<std::string> const& args)
return true;
}
-/*struct InstallPart
-{
- InstallPart(cmCommandArgumentsHelper* helper, const char* key,
- cmCommandArgumentGroup* group);
- cmCAStringVector argVector;
- cmInstallCommandArguments args;
-};*/
-
bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
{
// This is the TARGETS mode.
std::vector<cmTarget*> targets;
- cmCommandArgumentsHelper argHelper;
- cmCommandArgumentGroup group;
- cmCAStringVector genericArgVector(&argHelper, nullptr);
- cmCAStringVector archiveArgVector(&argHelper, "ARCHIVE", &group);
- cmCAStringVector libraryArgVector(&argHelper, "LIBRARY", &group);
- cmCAStringVector runtimeArgVector(&argHelper, "RUNTIME", &group);
- cmCAStringVector objectArgVector(&argHelper, "OBJECTS", &group);
- cmCAStringVector frameworkArgVector(&argHelper, "FRAMEWORK", &group);
- cmCAStringVector bundleArgVector(&argHelper, "BUNDLE", &group);
- cmCAStringVector includesArgVector(&argHelper, "INCLUDES", &group);
- cmCAStringVector privateHeaderArgVector(&argHelper, "PRIVATE_HEADER",
- &group);
- cmCAStringVector publicHeaderArgVector(&argHelper, "PUBLIC_HEADER", &group);
- cmCAStringVector resourceArgVector(&argHelper, "RESOURCE", &group);
- genericArgVector.Follows(nullptr);
- group.Follows(&genericArgVector);
-
- argHelper.Parse(&args, nullptr);
+ 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;
+ };
+
+ static auto const argHelper =
+ cmArgumentParser<ArgVectors>{}
+ .Bind("ARCHIVE"_s, &ArgVectors::Archive)
+ .Bind("LIBRARY"_s, &ArgVectors::Library)
+ .Bind("RUNTIME"_s, &ArgVectors::Runtime)
+ .Bind("OBJECTS"_s, &ArgVectors::Object)
+ .Bind("FRAMEWORK"_s, &ArgVectors::Framework)
+ .Bind("BUNDLE"_s, &ArgVectors::Bundle)
+ .Bind("INCLUDES"_s, &ArgVectors::Includes)
+ .Bind("PRIVATE_HEADER"_s, &ArgVectors::PrivateHeader)
+ .Bind("PUBLIC_HEADER"_s, &ArgVectors::PublicHeader)
+ .Bind("RESOURCE"_s, &ArgVectors::Resource);
+
+ std::vector<std::string> genericArgVector;
+ ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector);
// 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;
+ std::string exports;
std::vector<std::string> unknownArgs;
cmInstallCommandArguments genericArgs(this->DefaultComponentName);
- cmCAStringVector targetList(&genericArgs.Parser, "TARGETS");
- cmCAString exports(&genericArgs.Parser, "EXPORT",
- &genericArgs.ArgumentGroup);
- targetList.Follows(nullptr);
- genericArgs.ArgumentGroup.Follows(&targetList);
- genericArgs.Parse(&genericArgVector.GetVector(), &unknownArgs);
+ genericArgs.Bind("TARGETS"_s, targetList);
+ genericArgs.Bind("EXPORT"_s, exports);
+ genericArgs.Parse(genericArgVector, &unknownArgs);
bool success = genericArgs.Finalize();
cmInstallCommandArguments archiveArgs(this->DefaultComponentName);
@@ -277,16 +280,16 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
// now parse the args for specific parts of the target (e.g. LIBRARY,
// RUNTIME, ARCHIVE etc.
- archiveArgs.Parse(&archiveArgVector.GetVector(), &unknownArgs);
- libraryArgs.Parse(&libraryArgVector.GetVector(), &unknownArgs);
- runtimeArgs.Parse(&runtimeArgVector.GetVector(), &unknownArgs);
- objectArgs.Parse(&objectArgVector.GetVector(), &unknownArgs);
- frameworkArgs.Parse(&frameworkArgVector.GetVector(), &unknownArgs);
- bundleArgs.Parse(&bundleArgVector.GetVector(), &unknownArgs);
- privateHeaderArgs.Parse(&privateHeaderArgVector.GetVector(), &unknownArgs);
- publicHeaderArgs.Parse(&publicHeaderArgVector.GetVector(), &unknownArgs);
- resourceArgs.Parse(&resourceArgVector.GetVector(), &unknownArgs);
- includesArgs.Parse(&includesArgVector.GetVector(), &unknownArgs);
+ archiveArgs.Parse(argVectors.Archive, &unknownArgs);
+ libraryArgs.Parse(argVectors.Library, &unknownArgs);
+ runtimeArgs.Parse(argVectors.Runtime, &unknownArgs);
+ objectArgs.Parse(argVectors.Object, &unknownArgs);
+ frameworkArgs.Parse(argVectors.Framework, &unknownArgs);
+ bundleArgs.Parse(argVectors.Bundle, &unknownArgs);
+ privateHeaderArgs.Parse(argVectors.PrivateHeader, &unknownArgs);
+ publicHeaderArgs.Parse(argVectors.PublicHeader, &unknownArgs);
+ resourceArgs.Parse(argVectors.Resource, &unknownArgs);
+ includesArgs.Parse(&argVectors.Includes, &unknownArgs);
if (!unknownArgs.empty()) {
// Unknown argument.
@@ -382,7 +385,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
}
// Check if there is something to do.
- if (targetList.GetVector().empty()) {
+ if (targetList.empty()) {
return true;
}
@@ -390,7 +393,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
bool dll_platform =
!this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
- for (std::string const& tgt : targetList.GetVector()) {
+ for (std::string const& tgt : targetList) {
if (this->Makefile->IsAlias(tgt)) {
std::ostringstream e;
@@ -663,8 +666,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
// generators for them.
bool createInstallGeneratorsForTargetFileSets = true;
- if (target.IsFrameworkOnApple() ||
- target.GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+ if (target.IsFrameworkOnApple()) {
createInstallGeneratorsForTargetFileSets = false;
}
@@ -748,7 +750,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
// Add this install rule to an export if one was specified and
// this is not a namelink-only rule.
- if (!exports.GetString().empty() && !namelinkOnly) {
+ if (!exports.empty() && !namelinkOnly) {
cmTargetExport* te = new cmTargetExport;
te->TargetName = target.GetName();
te->ArchiveGenerator = archiveGenerator;
@@ -759,7 +761,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
te->RuntimeGenerator = runtimeGenerator;
te->ObjectsGenerator = objectGenerator;
this->Makefile->GetGlobalGenerator()
- ->GetExportSets()[exports.GetString()]
+ ->GetExportSets()[exports]
->AddTargetExport(te);
te->InterfaceIncludeDirectories =
@@ -818,11 +820,10 @@ bool cmInstallCommand::HandleFilesMode(std::vector<std::string> const& args)
// This is the FILES mode.
bool programs = (args[0] == "PROGRAMS");
cmInstallCommandArguments ica(this->DefaultComponentName);
- cmCAStringVector files(&ica.Parser, programs ? "PROGRAMS" : "FILES");
- files.Follows(nullptr);
- ica.ArgumentGroup.Follows(&files);
+ std::vector<std::string> files;
+ ica.Bind(programs ? "PROGRAMS"_s : "FILES"_s, files);
std::vector<std::string> unknownArgs;
- ica.Parse(&args, &unknownArgs);
+ ica.Parse(args, &unknownArgs);
if (!unknownArgs.empty()) {
// Unknown argument.
@@ -840,7 +841,7 @@ bool cmInstallCommand::HandleFilesMode(std::vector<std::string> const& args)
return false;
}
- const std::vector<std::string>& filesVector = files.GetVector();
+ const std::vector<std::string>& filesVector = files;
// Check if there is something to do.
if (filesVector.empty()) {
@@ -1271,16 +1272,19 @@ bool cmInstallCommand::HandleExportAndroidMKMode(
#ifdef CMAKE_BUILD_WITH_CMAKE
// This is the EXPORT mode.
cmInstallCommandArguments ica(this->DefaultComponentName);
- cmCAString exp(&ica.Parser, "EXPORT_ANDROID_MK");
- cmCAString name_space(&ica.Parser, "NAMESPACE", &ica.ArgumentGroup);
- cmCAEnabler exportOld(&ica.Parser, "EXPORT_LINK_INTERFACE_LIBRARIES",
- &ica.ArgumentGroup);
- cmCAString filename(&ica.Parser, "FILE", &ica.ArgumentGroup);
- exp.Follows(nullptr);
-
- ica.ArgumentGroup.Follows(&exp);
+
+ std::string exp;
+ std::string name_space;
+ bool exportOld = false;
+ std::string filename;
+
+ ica.Bind("EXPORT_ANDROID_MK"_s, exp);
+ ica.Bind("NAMESPACE"_s, name_space);
+ ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld);
+ ica.Bind("FILE"_s, filename);
+
std::vector<std::string> unknownArgs;
- ica.Parse(&args, &unknownArgs);
+ ica.Parse(args, &unknownArgs);
if (!unknownArgs.empty()) {
// Unknown argument.
@@ -1304,7 +1308,7 @@ bool cmInstallCommand::HandleExportAndroidMKMode(
}
// Check the file name.
- std::string fname = filename.GetString();
+ std::string fname = filename;
if (fname.find_first_of(":/\\") != std::string::npos) {
std::ostringstream e;
e << args[0] << " given invalid export file name \"" << fname << "\". "
@@ -1325,7 +1329,7 @@ bool cmInstallCommand::HandleExportAndroidMKMode(
}
if (fname.find_first_of(":/\\") != std::string::npos) {
std::ostringstream e;
- e << args[0] << " given export name \"" << exp.GetString() << "\". "
+ e << args[0] << " given export name \"" << exp << "\". "
<< "This name cannot be safely converted to a file name. "
<< "Specify a different export name or use the FILE option to set "
<< "a file name explicitly.";
@@ -1338,7 +1342,7 @@ bool cmInstallCommand::HandleExportAndroidMKMode(
}
cmExportSet* exportSet =
- this->Makefile->GetGlobalGenerator()->GetExportSets()[exp.GetString()];
+ this->Makefile->GetGlobalGenerator()->GetExportSets()[exp];
cmInstallGenerator::MessageLevel message =
cmInstallGenerator::SelectMessageLevel(this->Makefile);
@@ -1347,8 +1351,8 @@ bool cmInstallCommand::HandleExportAndroidMKMode(
cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator(
exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(),
ica.GetConfigurations(), ica.GetComponent().c_str(), message,
- ica.GetExcludeFromAll(), fname.c_str(), name_space.GetCString(),
- exportOld.IsEnabled(), true);
+ ica.GetExcludeFromAll(), fname.c_str(), name_space.c_str(), exportOld,
+ true);
this->Makefile->AddInstallGenerator(exportGenerator);
return true;
@@ -1363,16 +1367,19 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
{
// This is the EXPORT mode.
cmInstallCommandArguments ica(this->DefaultComponentName);
- cmCAString exp(&ica.Parser, "EXPORT");
- cmCAString name_space(&ica.Parser, "NAMESPACE", &ica.ArgumentGroup);
- cmCAEnabler exportOld(&ica.Parser, "EXPORT_LINK_INTERFACE_LIBRARIES",
- &ica.ArgumentGroup);
- cmCAString filename(&ica.Parser, "FILE", &ica.ArgumentGroup);
- exp.Follows(nullptr);
-
- ica.ArgumentGroup.Follows(&exp);
+
+ std::string exp;
+ std::string name_space;
+ bool exportOld = false;
+ std::string filename;
+
+ ica.Bind("EXPORT"_s, exp);
+ ica.Bind("NAMESPACE"_s, name_space);
+ ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld);
+ ica.Bind("FILE"_s, filename);
+
std::vector<std::string> unknownArgs;
- ica.Parse(&args, &unknownArgs);
+ ica.Parse(args, &unknownArgs);
if (!unknownArgs.empty()) {
// Unknown argument.
@@ -1396,7 +1403,7 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
}
// Check the file name.
- std::string fname = filename.GetString();
+ std::string fname = filename;
if (fname.find_first_of(":/\\") != std::string::npos) {
std::ostringstream e;
e << args[0] << " given invalid export file name \"" << fname << "\". "
@@ -1418,12 +1425,12 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
// Construct the file name.
if (fname.empty()) {
- fname = exp.GetString();
+ fname = exp;
fname += ".cmake";
if (fname.find_first_of(":/\\") != std::string::npos) {
std::ostringstream e;
- e << args[0] << " given export name \"" << exp.GetString() << "\". "
+ e << args[0] << " given export name \"" << exp << "\". "
<< "This name cannot be safely converted to a file name. "
<< "Specify a different export name or use the FILE option to set "
<< "a file name explicitly.";
@@ -1433,8 +1440,8 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
}
cmExportSet* exportSet =
- this->Makefile->GetGlobalGenerator()->GetExportSets()[exp.GetString()];
- if (exportOld.IsEnabled()) {
+ this->Makefile->GetGlobalGenerator()->GetExportSets()[exp];
+ if (exportOld) {
for (cmTargetExport* te : *exportSet->GetTargetExports()) {
cmTarget* tgt =
this->Makefile->GetGlobalGenerator()->FindTarget(te->TargetName);
@@ -1461,8 +1468,8 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args)
cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator(
exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(),
ica.GetConfigurations(), ica.GetComponent().c_str(), message,
- ica.GetExcludeFromAll(), fname.c_str(), name_space.GetCString(),
- exportOld.IsEnabled(), false);
+ ica.GetExcludeFromAll(), fname.c_str(), name_space.c_str(), exportOld,
+ false);
this->Makefile->AddInstallGenerator(exportGenerator);
return true;
diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx
index 155f0559b..8b33782ae 100644
--- a/Source/cmInstallCommandArguments.cxx
+++ b/Source/cmInstallCommandArguments.cxx
@@ -2,7 +2,9 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmInstallCommandArguments.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
+#include "cm_static_string_view.hxx"
#include <utility>
@@ -17,20 +19,19 @@ const std::string cmInstallCommandArguments::EmptyString;
cmInstallCommandArguments::cmInstallCommandArguments(
std::string defaultComponent)
- : Destination(&Parser, "DESTINATION", &ArgumentGroup)
- , Component(&Parser, "COMPONENT", &ArgumentGroup)
- , NamelinkComponent(&Parser, "NAMELINK_COMPONENT", &ArgumentGroup)
- , ExcludeFromAll(&Parser, "EXCLUDE_FROM_ALL", &ArgumentGroup)
- , Rename(&Parser, "RENAME", &ArgumentGroup)
- , Permissions(&Parser, "PERMISSIONS", &ArgumentGroup)
- , Configurations(&Parser, "CONFIGURATIONS", &ArgumentGroup)
- , Optional(&Parser, "OPTIONAL", &ArgumentGroup)
- , NamelinkOnly(&Parser, "NAMELINK_ONLY", &ArgumentGroup)
- , NamelinkSkip(&Parser, "NAMELINK_SKIP", &ArgumentGroup)
- , Type(&Parser, "TYPE", &ArgumentGroup)
- , GenericArguments(nullptr)
- , DefaultComponentName(std::move(defaultComponent))
+ : DefaultComponentName(std::move(defaultComponent))
{
+ this->Bind("DESTINATION"_s, this->Destination);
+ this->Bind("COMPONENT"_s, this->Component);
+ this->Bind("NAMELINK_COMPONENT"_s, this->NamelinkComponent);
+ this->Bind("EXCLUDE_FROM_ALL"_s, this->ExcludeFromAll);
+ this->Bind("RENAME"_s, this->Rename);
+ this->Bind("PERMISSIONS"_s, this->Permissions);
+ this->Bind("CONFIGURATIONS"_s, this->Configurations);
+ this->Bind("OPTIONAL"_s, this->Optional);
+ this->Bind("NAMELINK_ONLY"_s, this->NamelinkOnly);
+ this->Bind("NAMELINK_SKIP"_s, this->NamelinkSkip);
+ this->Bind("TYPE"_s, this->Type);
}
const std::string& cmInstallCommandArguments::GetDestination() const
@@ -46,8 +47,8 @@ const std::string& cmInstallCommandArguments::GetDestination() const
const std::string& cmInstallCommandArguments::GetComponent() const
{
- if (!this->Component.GetString().empty()) {
- return this->Component.GetString();
+ if (!this->Component.empty()) {
+ return this->Component;
}
if (this->GenericArguments != nullptr) {
return this->GenericArguments->GetComponent();
@@ -61,16 +62,16 @@ const std::string& cmInstallCommandArguments::GetComponent() const
const std::string& cmInstallCommandArguments::GetNamelinkComponent() const
{
- if (!this->NamelinkComponent.GetString().empty()) {
- return this->NamelinkComponent.GetString();
+ if (!this->NamelinkComponent.empty()) {
+ return this->NamelinkComponent;
}
return this->GetComponent();
}
const std::string& cmInstallCommandArguments::GetRename() const
{
- if (!this->Rename.GetString().empty()) {
- return this->Rename.GetString();
+ if (!this->Rename.empty()) {
+ return this->Rename;
}
if (this->GenericArguments != nullptr) {
return this->GenericArguments->GetRename();
@@ -91,7 +92,7 @@ const std::string& cmInstallCommandArguments::GetPermissions() const
bool cmInstallCommandArguments::GetOptional() const
{
- if (this->Optional.IsEnabled()) {
+ if (this->Optional) {
return true;
}
if (this->GenericArguments != nullptr) {
@@ -102,7 +103,7 @@ bool cmInstallCommandArguments::GetOptional() const
bool cmInstallCommandArguments::GetExcludeFromAll() const
{
- if (this->ExcludeFromAll.IsEnabled()) {
+ if (this->ExcludeFromAll) {
return true;
}
if (this->GenericArguments != nullptr) {
@@ -113,7 +114,7 @@ bool cmInstallCommandArguments::GetExcludeFromAll() const
bool cmInstallCommandArguments::GetNamelinkOnly() const
{
- if (this->NamelinkOnly.IsEnabled()) {
+ if (this->NamelinkOnly) {
return true;
}
if (this->GenericArguments != nullptr) {
@@ -124,7 +125,7 @@ bool cmInstallCommandArguments::GetNamelinkOnly() const
bool cmInstallCommandArguments::GetNamelinkSkip() const
{
- if (this->NamelinkSkip.IsEnabled()) {
+ if (this->NamelinkSkip) {
return true;
}
if (this->GenericArguments != nullptr) {
@@ -135,7 +136,7 @@ bool cmInstallCommandArguments::GetNamelinkSkip() const
bool cmInstallCommandArguments::HasNamelinkComponent() const
{
- if (!this->NamelinkComponent.GetString().empty()) {
+ if (!this->NamelinkComponent.empty()) {
return true;
}
if (this->GenericArguments != nullptr) {
@@ -146,19 +147,19 @@ bool cmInstallCommandArguments::HasNamelinkComponent() const
const std::string& cmInstallCommandArguments::GetType() const
{
- return this->Type.GetString();
+ return this->Type;
}
const std::vector<std::string>& cmInstallCommandArguments::GetConfigurations()
const
{
- if (!this->Configurations.GetVector().empty()) {
- return this->Configurations.GetVector();
+ if (!this->Configurations.empty()) {
+ return this->Configurations;
}
if (this->GenericArguments != nullptr) {
return this->GenericArguments->GetConfigurations();
}
- return this->Configurations.GetVector();
+ return this->Configurations;
}
bool cmInstallCommandArguments::Finalize()
@@ -166,21 +167,15 @@ bool cmInstallCommandArguments::Finalize()
if (!this->CheckPermissions()) {
return false;
}
- this->DestinationString = this->Destination.GetString();
+ this->DestinationString = this->Destination;
cmSystemTools::ConvertToUnixSlashes(this->DestinationString);
return true;
}
-void cmInstallCommandArguments::Parse(const std::vector<std::string>* args,
- std::vector<std::string>* unconsumedArgs)
-{
- this->Parser.Parse(args, unconsumedArgs);
-}
-
bool cmInstallCommandArguments::CheckPermissions()
{
this->PermissionsString.clear();
- for (std::string const& perm : this->Permissions.GetVector()) {
+ for (std::string const& perm : this->Permissions) {
if (!cmInstallCommandArguments::CheckPermissions(
perm, this->PermissionsString)) {
return false;
@@ -220,10 +215,7 @@ void cmInstallCommandIncludesArgument::Parse(
if (args->empty()) {
return;
}
- std::vector<std::string>::const_iterator it = args->begin();
- ++it;
- for (; it != args->end(); ++it) {
- std::string dir = *it;
+ for (std::string dir : cmMakeRange(*args).advance(1)) {
cmSystemTools::ConvertToUnixSlashes(dir);
this->IncludeDirs.push_back(std::move(dir));
}
diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h
index 9c0d41763..5d2ee0ab4 100644
--- a/Source/cmInstallCommandArguments.h
+++ b/Source/cmInstallCommandArguments.h
@@ -8,9 +8,9 @@
#include <string>
#include <vector>
-#include "cmCommandArgumentsHelper.h"
+#include "cmArgumentParser.h"
-class cmInstallCommandArguments
+class cmInstallCommandArguments : public cmArgumentParser<void>
{
public:
cmInstallCommandArguments(std::string defaultComponent);
@@ -18,8 +18,6 @@ public:
{
this->GenericArguments = args;
}
- void Parse(const std::vector<std::string>* args,
- std::vector<std::string>* unconsumedArgs);
// Compute destination path.and check permissions
bool Finalize();
@@ -37,30 +35,25 @@ public:
bool HasNamelinkComponent() const;
const std::string& GetType() const;
- // once HandleDirectoryMode() is also switched to using
- // cmInstallCommandArguments then these two functions can become non-static
- // private member functions without arguments
static bool CheckPermissions(const std::string& onePerm, std::string& perm);
- cmCommandArgumentsHelper Parser;
- cmCommandArgumentGroup ArgumentGroup;
private:
- cmCAString Destination;
- cmCAString Component;
- cmCAString NamelinkComponent;
- cmCAEnabler ExcludeFromAll;
- cmCAString Rename;
- cmCAStringVector Permissions;
- cmCAStringVector Configurations;
- cmCAEnabler Optional;
- cmCAEnabler NamelinkOnly;
- cmCAEnabler NamelinkSkip;
- cmCAString Type;
+ std::string Destination;
+ std::string Component;
+ std::string NamelinkComponent;
+ bool ExcludeFromAll = false;
+ std::string Rename;
+ std::vector<std::string> Permissions;
+ std::vector<std::string> Configurations;
+ bool Optional = false;
+ bool NamelinkOnly = false;
+ bool NamelinkSkip = false;
+ std::string Type;
std::string DestinationString;
std::string PermissionsString;
- cmInstallCommandArguments* GenericArguments;
+ cmInstallCommandArguments* GenericArguments = nullptr;
static const char* PermissionsTable[];
static const std::string EmptyString;
std::string DefaultComponentName;
diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx
index a88c7af3b..14288f6d2 100644
--- a/Source/cmInstallDirectoryGenerator.cxx
+++ b/Source/cmInstallDirectoryGenerator.cxx
@@ -31,19 +31,22 @@ cmInstallDirectoryGenerator::cmInstallDirectoryGenerator(
}
// We need per-config actions if any directories have generator expressions.
- for (std::vector<std::string>::const_iterator i = dirs.begin();
- !this->ActionsPerConfig && i != dirs.end(); ++i) {
- if (cmGeneratorExpression::Find(*i) != std::string::npos) {
- this->ActionsPerConfig = true;
+ if (!this->ActionsPerConfig) {
+ for (std::string const& dir : dirs) {
+ if (cmGeneratorExpression::Find(dir) != std::string::npos) {
+ this->ActionsPerConfig = true;
+ break;
+ }
}
}
}
cmInstallDirectoryGenerator::~cmInstallDirectoryGenerator() = default;
-void cmInstallDirectoryGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallDirectoryGenerator::Compute(cmLocalGenerator* lg)
{
- LocalGenerator = lg;
+ this->LocalGenerator = lg;
+ return true;
}
void cmInstallDirectoryGenerator::GenerateScriptActions(std::ostream& os,
diff --git a/Source/cmInstallDirectoryGenerator.h b/Source/cmInstallDirectoryGenerator.h
index ac6e50457..e30849f83 100644
--- a/Source/cmInstallDirectoryGenerator.h
+++ b/Source/cmInstallDirectoryGenerator.h
@@ -29,7 +29,7 @@ public:
bool optional = false);
~cmInstallDirectoryGenerator() override;
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
std::string GetDestination(std::string const& config) const;
diff --git a/Source/cmInstallExportAndroidMKGenerator.cxx b/Source/cmInstallExportAndroidMKGenerator.cxx
index 85b702142..55d368507 100644
--- a/Source/cmInstallExportAndroidMKGenerator.cxx
+++ b/Source/cmInstallExportAndroidMKGenerator.cxx
@@ -30,10 +30,11 @@ cmInstallExportAndroidMKGenerator::~cmInstallExportAndroidMKGenerator()
{
}
-void cmInstallExportAndroidMKGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallExportAndroidMKGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
this->ExportSet->Compute(lg);
+ return true;
}
void cmInstallExportAndroidMKGenerator::GenerateScript(std::ostream& os)
@@ -43,7 +44,7 @@ void cmInstallExportAndroidMKGenerator::GenerateScript(std::ostream& os)
std::ostringstream e;
e << "INSTALL(EXPORT) given unknown export \"" << ExportSet->GetName()
<< "\"";
- cmSystemTools::Error(e.str().c_str());
+ cmSystemTools::Error(e.str());
return;
}
@@ -67,10 +68,8 @@ void cmInstallExportAndroidMKGenerator::GenerateScript(std::ostream& os)
this->EFGen->AddConfiguration("");
}
} else {
- for (std::vector<std::string>::const_iterator ci =
- this->ConfigurationTypes->begin();
- ci != this->ConfigurationTypes->end(); ++ci) {
- this->EFGen->AddConfiguration(*ci);
+ for (std::string const& config : this->ConfigurationTypes) {
+ this->EFGen->AddConfiguration(config);
}
}
this->EFGen->GenerateImportFile();
@@ -88,11 +87,9 @@ void cmInstallExportAndroidMKGenerator::GenerateScriptConfigs(
// Now create a configuration-specific install rule for the import
// file of each configuration.
std::vector<std::string> files;
- for (std::map<std::string, std::string>::const_iterator i =
- this->EFGen->GetConfigImportFiles().begin();
- i != this->EFGen->GetConfigImportFiles().end(); ++i) {
- files.push_back(i->second);
- std::string config_test = this->CreateConfigTest(i->first);
+ for (auto const& pair : this->EFGen->GetConfigImportFiles()) {
+ files.push_back(pair.second);
+ std::string config_test = this->CreateConfigTest(pair.first);
os << indent << "if(" << config_test << ")\n";
this->AddInstallRule(os, this->Destination, cmInstallType_FILES, files,
false, this->FilePermissions.c_str(), nullptr,
diff --git a/Source/cmInstallExportAndroidMKGenerator.h b/Source/cmInstallExportAndroidMKGenerator.h
index 189084a1a..a92ff27f1 100644
--- a/Source/cmInstallExportAndroidMKGenerator.h
+++ b/Source/cmInstallExportAndroidMKGenerator.h
@@ -24,7 +24,7 @@ public:
const char* name_space, bool exportOld);
~cmInstallExportAndroidMKGenerator();
- void Compute(cmLocalGenerator* lg);
+ bool Compute(cmLocalGenerator* lg) override;
protected:
virtual void GenerateScript(std::ostream& os);
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx
index 47b9785e5..f5bedabc4 100644
--- a/Source/cmInstallExportGenerator.cxx
+++ b/Source/cmInstallExportGenerator.cxx
@@ -45,10 +45,11 @@ cmInstallExportGenerator::~cmInstallExportGenerator()
delete this->EFGen;
}
-void cmInstallExportGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallExportGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
this->ExportSet->Compute(lg);
+ return true;
}
void cmInstallExportGenerator::ComputeTempDir()
@@ -202,7 +203,7 @@ void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os,
os << indentNN << "file(GLOB OLD_CONFIG_FILES \"" << installedDir
<< this->EFGen->GetConfigImportFileGlob() << "\")\n";
os << indentNN << "if(OLD_CONFIG_FILES)\n";
- os << indentNNN << "message(STATUS \"Old export file \\\"" << installedFile
+ os << indentNNN << R"(message(STATUS "Old export file \")" << installedFile
<< "\\\" will be replaced. Removing files [${OLD_CONFIG_FILES}].\")\n";
os << indentNNN << "file(REMOVE ${OLD_CONFIG_FILES})\n";
os << indentNN << "endif()\n";
diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h
index d23cf063d..c4d252c47 100644
--- a/Source/cmInstallExportGenerator.h
+++ b/Source/cmInstallExportGenerator.h
@@ -34,7 +34,7 @@ public:
cmExportSet* GetExportSet() { return this->ExportSet; }
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
cmLocalGenerator* GetLocalGenerator() const { return this->LocalGenerator; }
diff --git a/Source/cmInstallFilesCommand.cxx b/Source/cmInstallFilesCommand.cxx
index 4dde18fb0..efbcb6713 100644
--- a/Source/cmInstallFilesCommand.cxx
+++ b/Source/cmInstallFilesCommand.cxx
@@ -2,11 +2,13 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmInstallFilesCommand.h"
+#include "cmAlgorithms.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
#include "cmInstallFilesGenerator.h"
#include "cmInstallGenerator.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
class cmExecutionStatus;
@@ -27,16 +29,14 @@ bool cmInstallFilesCommand::InitialPass(std::vector<std::string> const& args,
if ((args.size() > 1) && (args[1] == "FILES")) {
this->IsFilesForm = true;
- for (std::vector<std::string>::const_iterator s = args.begin() + 2;
- s != args.end(); ++s) {
+ for (std::string const& arg : cmMakeRange(args).advance(2)) {
// Find the source location for each file listed.
- this->Files.push_back(this->FindInstallSource(s->c_str()));
+ this->Files.push_back(this->FindInstallSource(arg.c_str()));
}
this->CreateInstallGenerator();
} else {
this->IsFilesForm = false;
- this->FinalArgs.insert(this->FinalArgs.end(), args.begin() + 1,
- args.end());
+ cmAppend(this->FinalArgs, args.begin() + 1, args.end());
}
this->Makefile->GetGlobalGenerator()->AddInstallComponent(
diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx
index 07094cb68..2ed9f734d 100644
--- a/Source/cmInstallFilesGenerator.cxx
+++ b/Source/cmInstallFilesGenerator.cxx
@@ -29,20 +29,23 @@ cmInstallFilesGenerator::cmInstallFilesGenerator(
this->ActionsPerConfig = true;
}
- // We need per-config actions if any files have generator expressions.
- for (std::vector<std::string>::const_iterator i = files.begin();
- !this->ActionsPerConfig && i != files.end(); ++i) {
- if (cmGeneratorExpression::Find(*i) != std::string::npos) {
- this->ActionsPerConfig = true;
+ // We need per-config actions if any directories have generator expressions.
+ if (!this->ActionsPerConfig) {
+ for (std::string const& file : files) {
+ if (cmGeneratorExpression::Find(file) != std::string::npos) {
+ this->ActionsPerConfig = true;
+ break;
+ }
}
}
}
cmInstallFilesGenerator::~cmInstallFilesGenerator() = default;
-void cmInstallFilesGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallFilesGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
+ return true;
}
std::string cmInstallFilesGenerator::GetDestination(
diff --git a/Source/cmInstallFilesGenerator.h b/Source/cmInstallFilesGenerator.h
index 0ef2a06b0..ac462d46f 100644
--- a/Source/cmInstallFilesGenerator.h
+++ b/Source/cmInstallFilesGenerator.h
@@ -29,7 +29,7 @@ public:
bool optional = false);
~cmInstallFilesGenerator() override;
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
std::string GetDestination(std::string const& config) const;
diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
index d139190a4..2ffca30f6 100644
--- a/Source/cmInstallGenerator.cxx
+++ b/Source/cmInstallGenerator.cxx
@@ -69,17 +69,18 @@ void cmInstallGenerator::AddInstallRule(
if (cmSystemTools::FileIsFullPath(dest)) {
os << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n";
os << indent << " \"";
- for (std::vector<std::string>::const_iterator fi = files.begin();
- fi != files.end(); ++fi) {
- if (fi != files.begin()) {
+ bool firstIteration = true;
+ for (std::string const& file : files) {
+ if (!firstIteration) {
os << ";";
}
os << dest << "/";
if (rename && *rename) {
os << rename;
} else {
- os << cmSystemTools::GetFilenameName(*fi);
+ os << cmSystemTools::GetFilenameName(file);
}
+ firstIteration = false;
}
os << "\")\n";
os << indent << "if(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n";
@@ -141,7 +142,7 @@ void cmInstallGenerator::AddInstallRule(
std::string cmInstallGenerator::CreateComponentTest(const char* component,
bool exclude_from_all)
{
- std::string result = "\"x${CMAKE_INSTALL_COMPONENT}x\" STREQUAL \"x";
+ std::string result = R"("x${CMAKE_INSTALL_COMPONENT}x" STREQUAL "x)";
result += component;
result += "x\"";
if (!exclude_from_all) {
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
index 9bd7ac318..dbe707d1d 100644
--- a/Source/cmInstallGenerator.h
+++ b/Source/cmInstallGenerator.h
@@ -60,7 +60,7 @@ public:
/** Select message level from CMAKE_INSTALL_MESSAGE or 'never'. */
static MessageLevel SelectMessageLevel(cmMakefile* mf, bool never = false);
- virtual void Compute(cmLocalGenerator*) {}
+ virtual bool Compute(cmLocalGenerator*) { return true; }
protected:
void GenerateScript(std::ostream& os) override;
diff --git a/Source/cmInstallProgramsCommand.cxx b/Source/cmInstallProgramsCommand.cxx
index f01a4c1c4..a58f87578 100644
--- a/Source/cmInstallProgramsCommand.cxx
+++ b/Source/cmInstallProgramsCommand.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmInstallProgramsCommand.h"
+#include "cmAlgorithms.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h"
#include "cmInstallFilesGenerator.h"
@@ -25,7 +26,7 @@ bool cmInstallProgramsCommand::InitialPass(
this->Destination = args[0];
- this->FinalArgs.insert(this->FinalArgs.end(), args.begin() + 1, args.end());
+ cmAppend(this->FinalArgs, args.begin() + 1, args.end());
this->Makefile->GetGlobalGenerator()->AddInstallComponent(
this->Makefile->GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"));
diff --git a/Source/cmInstallScriptGenerator.cxx b/Source/cmInstallScriptGenerator.cxx
index a513958ed..5832d27e6 100644
--- a/Source/cmInstallScriptGenerator.cxx
+++ b/Source/cmInstallScriptGenerator.cxx
@@ -29,7 +29,7 @@ cmInstallScriptGenerator::cmInstallScriptGenerator(const char* script,
cmInstallScriptGenerator::~cmInstallScriptGenerator() = default;
-void cmInstallScriptGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallScriptGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
@@ -49,6 +49,8 @@ void cmInstallScriptGenerator::Compute(cmLocalGenerator* lg)
break;
}
}
+
+ return true;
}
void cmInstallScriptGenerator::AddScriptInstallRule(std::ostream& os,
diff --git a/Source/cmInstallScriptGenerator.h b/Source/cmInstallScriptGenerator.h
index 05199d790..6af737113 100644
--- a/Source/cmInstallScriptGenerator.h
+++ b/Source/cmInstallScriptGenerator.h
@@ -23,7 +23,7 @@ public:
const char* component, bool exclude_from_all);
~cmInstallScriptGenerator() override;
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
protected:
void GenerateScriptActions(std::ostream& os, Indent indent) override;
diff --git a/Source/cmInstallSubdirectoryGenerator.cxx b/Source/cmInstallSubdirectoryGenerator.cxx
index ad7121f2e..1c0512ce5 100644
--- a/Source/cmInstallSubdirectoryGenerator.cxx
+++ b/Source/cmInstallSubdirectoryGenerator.cxx
@@ -41,9 +41,10 @@ void cmInstallSubdirectoryGenerator::CheckCMP0082(
}
}
-void cmInstallSubdirectoryGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallSubdirectoryGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
+ return true;
}
void cmInstallSubdirectoryGenerator::GenerateScript(std::ostream& os)
diff --git a/Source/cmInstallSubdirectoryGenerator.h b/Source/cmInstallSubdirectoryGenerator.h
index 35471dda0..22759d948 100644
--- a/Source/cmInstallSubdirectoryGenerator.h
+++ b/Source/cmInstallSubdirectoryGenerator.h
@@ -28,7 +28,7 @@ public:
void CheckCMP0082(bool& haveSubdirectoryInstall,
bool& haveInstallAfterSubdirectory) override;
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
protected:
void GenerateScript(std::ostream& os) override;
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index 9d3a6bb60..7c5a55bb6 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -107,19 +107,15 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
// There is a bug in cmInstallCommand if this fails.
assert(this->NamelinkMode == NamelinkModeNone);
- std::string targetName;
- std::string targetNameReal;
- std::string targetNameImport;
- std::string targetNamePDB;
- this->Target->GetExecutableNames(targetName, targetNameReal,
- targetNameImport, targetNamePDB, config);
+ cmGeneratorTarget::Names targetNames =
+ this->Target->GetExecutableNames(config);
if (this->ImportLibrary) {
- std::string from1 = fromDirConfig + targetNameImport;
- std::string to1 = toDir + targetNameImport;
+ std::string from1 = fromDirConfig + targetNames.ImportLibrary;
+ std::string to1 = toDir + targetNames.ImportLibrary;
filesFrom.push_back(std::move(from1));
filesTo.push_back(std::move(to1));
std::string targetNameImportLib;
- if (this->Target->GetImplibGNUtoMS(config, targetNameImport,
+ if (this->Target->GetImplibGNUtoMS(config, targetNames.ImportLibrary,
targetNameImportLib)) {
filesFrom.push_back(fromDirConfig + targetNameImportLib);
filesTo.push_back(toDir + targetNameImportLib);
@@ -128,8 +124,8 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
// An import library looks like a static library.
type = cmInstallType_STATIC_LIBRARY;
} else {
- std::string from1 = fromDirConfig + targetName;
- std::string to1 = toDir + targetName;
+ std::string from1 = fromDirConfig + targetNames.Output;
+ std::string to1 = toDir + targetNames.Output;
// Handle OSX Bundles.
if (this->Target->IsAppBundleOnApple()) {
@@ -154,12 +150,12 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
if (!mf->PlatformIsAppleEmbedded()) {
to1 += "Contents/MacOS/";
}
- to1 += targetName;
+ to1 += targetNames.Output;
} else {
// Tweaks apply to the real file, so list it first.
- if (targetNameReal != targetName) {
- std::string from2 = fromDirConfig + targetNameReal;
- std::string to2 = toDir += targetNameReal;
+ if (targetNames.Real != targetNames.Output) {
+ std::string from2 = fromDirConfig + targetNames.Real;
+ std::string to2 = toDir += targetNames.Real;
filesFrom.push_back(std::move(from2));
filesTo.push_back(std::move(to2));
}
@@ -169,23 +165,18 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
filesTo.push_back(std::move(to1));
}
} else {
- std::string targetName;
- std::string targetNameSO;
- std::string targetNameReal;
- std::string targetNameImport;
- std::string targetNamePDB;
- this->Target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
- targetNameImport, targetNamePDB, config);
+ cmGeneratorTarget::Names targetNames =
+ this->Target->GetLibraryNames(config);
if (this->ImportLibrary) {
// There is a bug in cmInstallCommand if this fails.
assert(this->NamelinkMode == NamelinkModeNone);
- std::string from1 = fromDirConfig + targetNameImport;
- std::string to1 = toDir + targetNameImport;
+ std::string from1 = fromDirConfig + targetNames.ImportLibrary;
+ std::string to1 = toDir + targetNames.ImportLibrary;
filesFrom.push_back(std::move(from1));
filesTo.push_back(std::move(to1));
std::string targetNameImportLib;
- if (this->Target->GetImplibGNUtoMS(config, targetNameImport,
+ if (this->Target->GetImplibGNUtoMS(config, targetNames.ImportLibrary,
targetNameImportLib)) {
filesFrom.push_back(fromDirConfig + targetNameImportLib);
filesTo.push_back(toDir + targetNameImportLib);
@@ -227,11 +218,11 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
type = cmInstallType_DIRECTORY;
literal_args += " USE_SOURCE_PERMISSIONS";
- std::string from1 = fromDirConfig + targetName;
+ std::string from1 = fromDirConfig + targetNames.Output;
from1 = cmSystemTools::GetFilenamePath(from1);
// Tweaks apply to the binary inside the bundle.
- std::string to1 = toDir + targetNameReal;
+ std::string to1 = toDir + targetNames.Real;
filesFrom.push_back(std::move(from1));
filesTo.push_back(std::move(to1));
@@ -240,10 +231,11 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
type = cmInstallType_DIRECTORY;
literal_args += " USE_SOURCE_PERMISSIONS";
- std::string targetNameBase = targetName.substr(0, targetName.find('/'));
+ std::string targetNameBase =
+ targetNames.Output.substr(0, targetNames.Output.find('/'));
std::string from1 = fromDirConfig + targetNameBase;
- std::string to1 = toDir + targetName;
+ std::string to1 = toDir + targetNames.Output;
filesFrom.push_back(std::move(from1));
filesTo.push_back(std::move(to1));
@@ -251,25 +243,26 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
bool haveNamelink = false;
// Library link name.
- std::string fromName = fromDirConfig + targetName;
- std::string toName = toDir + targetName;
+ std::string fromName = fromDirConfig + targetNames.Output;
+ std::string toName = toDir + targetNames.Output;
// Library interface name.
std::string fromSOName;
std::string toSOName;
- if (targetNameSO != targetName) {
+ if (targetNames.SharedObject != targetNames.Output) {
haveNamelink = true;
- fromSOName = fromDirConfig + targetNameSO;
- toSOName = toDir + targetNameSO;
+ fromSOName = fromDirConfig + targetNames.SharedObject;
+ toSOName = toDir + targetNames.SharedObject;
}
// Library implementation name.
std::string fromRealName;
std::string toRealName;
- if (targetNameReal != targetName && targetNameReal != targetNameSO) {
+ if (targetNames.Real != targetNames.Output &&
+ targetNames.Real != targetNames.SharedObject) {
haveNamelink = true;
- fromRealName = fromDirConfig + targetNameReal;
- toRealName = toDir + targetNameReal;
+ fromRealName = fromDirConfig + targetNames.Real;
+ toRealName = toDir + targetNames.Real;
}
// Add the names based on the current namelink mode.
@@ -400,55 +393,44 @@ std::string cmInstallTargetGenerator::GetInstallFilename(
std::string fname;
// Compute the name of the library.
if (target->GetType() == cmStateEnums::EXECUTABLE) {
- std::string targetName;
- std::string targetNameReal;
- std::string targetNameImport;
- std::string targetNamePDB;
- target->GetExecutableNames(targetName, targetNameReal, targetNameImport,
- targetNamePDB, config);
+ cmGeneratorTarget::Names targetNames = target->GetExecutableNames(config);
if (nameType == NameImplib) {
// Use the import library name.
- if (!target->GetImplibGNUtoMS(config, targetNameImport, fname,
+ if (!target->GetImplibGNUtoMS(config, targetNames.ImportLibrary, fname,
"${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
- fname = targetNameImport;
+ fname = targetNames.ImportLibrary;
}
} else if (nameType == NameReal) {
// Use the canonical name.
- fname = targetNameReal;
+ fname = targetNames.Real;
} else {
// Use the canonical name.
- fname = targetName;
+ fname = targetNames.Output;
}
} else {
- std::string targetName;
- std::string targetNameSO;
- std::string targetNameReal;
- std::string targetNameImport;
- std::string targetNamePDB;
- target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
- targetNameImport, targetNamePDB, config);
+ cmGeneratorTarget::Names targetNames = target->GetLibraryNames(config);
if (nameType == NameImplib) {
// Use the import library name.
- if (!target->GetImplibGNUtoMS(config, targetNameImport, fname,
+ if (!target->GetImplibGNUtoMS(config, targetNames.ImportLibrary, fname,
"${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
- fname = targetNameImport;
+ fname = targetNames.ImportLibrary;
}
} else if (nameType == NameSO) {
// Use the soname.
- fname = targetNameSO;
+ fname = targetNames.SharedObject;
} else if (nameType == NameReal) {
// Use the real name.
- fname = targetNameReal;
+ fname = targetNames.Real;
} else {
// Use the canonical name.
- fname = targetName;
+ fname = targetNames.Output;
}
}
return fname;
}
-void cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
{
// Lookup this target in the current directory.
this->Target = lg->FindLocalNonAliasGeneratorTarget(this->TargetName);
@@ -457,6 +439,8 @@ void cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
this->Target =
lg->GetGlobalGenerator()->FindGeneratorTarget(this->TargetName);
}
+
+ return true;
}
void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent,
@@ -809,7 +793,7 @@ void cmInstallTargetGenerator::AddRanlibRule(std::ostream& os, Indent indent,
return;
}
- std::string ranlib =
+ const std::string& ranlib =
this->Target->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
if (ranlib.empty()) {
return;
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index 6df5b1a50..ed3ab5246 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -58,7 +58,7 @@ public:
const std::string& config,
NameType nameType = NameNormal);
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
cmGeneratorTarget* GetTarget() const { return this->Target; }
diff --git a/Source/cmInstallTargetsCommand.cxx b/Source/cmInstallTargetsCommand.cxx
index d721ca0ee..ef07e2cf4 100644
--- a/Source/cmInstallTargetsCommand.cxx
+++ b/Source/cmInstallTargetsCommand.cxx
@@ -23,7 +23,7 @@ bool cmInstallTargetsCommand::InitialPass(std::vector<std::string> const& args,
// Enable the install target.
this->Makefile->GetGlobalGenerator()->EnableInstallTarget();
- cmTargets& tgts = this->Makefile->GetTargets();
+ cmMakefile::cmTargetMap& tgts = this->Makefile->GetTargets();
std::vector<std::string>::const_iterator s = args.begin();
++s;
std::string runtime_dir = "/bin";
@@ -38,10 +38,10 @@ bool cmInstallTargetsCommand::InitialPass(std::vector<std::string> const& args,
runtime_dir = *s;
} else {
- cmTargets::iterator ti = tgts.find(*s);
+ cmMakefile::cmTargetMap::iterator ti = tgts.find(*s);
if (ti != tgts.end()) {
- ti->second.SetInstallPath(args[0].c_str());
- ti->second.SetRuntimeInstallPath(runtime_dir.c_str());
+ ti->second.SetInstallPath(args[0]);
+ ti->second.SetRuntimeInstallPath(runtime_dir);
ti->second.SetHaveInstallRule(true);
} else {
std::string str = "Cannot find target: \"" + *s + "\" to install.";
diff --git a/Source/cmInstalledFile.h b/Source/cmInstalledFile.h
index 070b954e6..b7d602ef4 100644
--- a/Source/cmInstalledFile.h
+++ b/Source/cmInstalledFile.h
@@ -32,6 +32,9 @@ public:
Property();
~Property();
+ Property(const Property&) = delete;
+ Property& operator=(const Property&) = delete;
+
ExpressionVectorType ValueExpressions;
};
@@ -41,6 +44,9 @@ public:
~cmInstalledFile();
+ cmInstalledFile(const cmInstalledFile&) = delete;
+ cmInstalledFile& operator=(const cmInstalledFile&) = delete;
+
void RemoveProperty(const std::string& prop);
void SetProperty(cmMakefile const* mf, const std::string& prop,
diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx
index d723cedb5..636a8e1c2 100644
--- a/Source/cmJsonObjects.cxx
+++ b/Source/cmJsonObjects.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmJsonObjects.h" // IWYU pragma: keep
+#include "cmAlgorithms.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
@@ -601,8 +602,7 @@ static Json::Value DumpTargetsList(
std::vector<cmGeneratorTarget*> targetList;
for (auto const& lgIt : generators) {
- const auto& list = lgIt->GetGeneratorTargets();
- targetList.insert(targetList.end(), list.begin(), list.end());
+ cmAppend(targetList, lgIt->GetGeneratorTargets());
}
std::sort(targetList.begin(), targetList.end());
diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx
index 211d03bd8..8d2add635 100644
--- a/Source/cmLinkLineDeviceComputer.cxx
+++ b/Source/cmLinkLineDeviceComputer.cxx
@@ -3,15 +3,21 @@
#include "cmLinkLineDeviceComputer.h"
+#include <algorithm>
#include <set>
#include <sstream>
#include <utility>
+#include <vector>
#include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h"
#include "cmGeneratorTarget.h"
-#include "cmGlobalNinjaGenerator.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
#include "cmStateTypes.h"
+#include "cmSystemTools.h"
class cmOutputConverter;
@@ -41,6 +47,27 @@ static bool cmLinkItemValidForDevice(std::string const& item)
cmHasLiteralPrefix(item, "--library"));
}
+bool cmLinkLineDeviceComputer::ComputeRequiresDeviceLinking(
+ cmComputeLinkInformation& cli)
+{
+ // Determine if this item might requires device linking.
+ // For this we only consider targets
+ typedef cmComputeLinkInformation::ItemVector ItemVector;
+ ItemVector const& items = cli.GetItems();
+ std::string config = cli.GetConfig();
+ for (auto const& item : items) {
+ if (item.Target &&
+ item.Target->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ if ((!item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS")) &&
+ item.Target->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION")) {
+ // this dependency requires us to device link it
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
std::string cmLinkLineDeviceComputer::ComputeLinkLibraries(
cmComputeLinkInformation& cli, std::string const& stdLibString)
{
@@ -118,16 +145,58 @@ std::string cmLinkLineDeviceComputer::GetLinkerLanguage(cmGeneratorTarget*,
return "CUDA";
}
-cmNinjaLinkLineDeviceComputer::cmNinjaLinkLineDeviceComputer(
- cmOutputConverter* outputConverter, cmStateDirectory const& stateDir,
- cmGlobalNinjaGenerator const* gg)
- : cmLinkLineDeviceComputer(outputConverter, stateDir)
- , GG(gg)
+bool requireDeviceLinking(cmGeneratorTarget& target, cmLocalGenerator& lg,
+ const std::string& config)
{
-}
+ if (!target.GetGlobalGenerator()->GetLanguageEnabled("CUDA")) {
+ return false;
+ }
-std::string cmNinjaLinkLineDeviceComputer::ConvertToLinkReference(
- std::string const& lib) const
-{
- return GG->ConvertToNinjaPath(lib);
+ if (target.GetType() == cmStateEnums::OBJECT_LIBRARY) {
+ return false;
+ }
+
+ if (const char* resolveDeviceSymbols =
+ target.GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
+ // If CUDA_RESOLVE_DEVICE_SYMBOLS has been explicitly set we need
+ // to honor the value no matter what it is.
+ return cmSystemTools::IsOn(resolveDeviceSymbols);
+ }
+
+ if (const char* separableCompilation =
+ target.GetProperty("CUDA_SEPARABLE_COMPILATION")) {
+ if (cmSystemTools::IsOn(separableCompilation)) {
+ bool doDeviceLinking = false;
+ switch (target.GetType()) {
+ case cmStateEnums::SHARED_LIBRARY:
+ case cmStateEnums::MODULE_LIBRARY:
+ case cmStateEnums::EXECUTABLE:
+ doDeviceLinking = true;
+ break;
+ default:
+ break;
+ }
+ return doDeviceLinking;
+ }
+ }
+
+ // Determine if we have any dependencies that require
+ // us to do a device link step
+ const std::string cuda_lang("CUDA");
+ cmGeneratorTarget::LinkClosure const* closure =
+ target.GetLinkClosure(config);
+
+ bool closureHasCUDA =
+ (std::find(closure->Languages.begin(), closure->Languages.end(),
+ cuda_lang) != closure->Languages.end());
+ if (closureHasCUDA) {
+ cmComputeLinkInformation* pcli = target.GetLinkInformation(config);
+ if (pcli) {
+ cmLinkLineDeviceComputer deviceLinkComputer(
+ &lg, lg.GetStateSnapshot().GetDirectory());
+ return deviceLinkComputer.ComputeRequiresDeviceLinking(*pcli);
+ }
+ return true;
+ }
+ return false;
}
diff --git a/Source/cmLinkLineDeviceComputer.h b/Source/cmLinkLineDeviceComputer.h
index cf66f6475..0ea5f69e7 100644
--- a/Source/cmLinkLineDeviceComputer.h
+++ b/Source/cmLinkLineDeviceComputer.h
@@ -12,7 +12,7 @@
class cmComputeLinkInformation;
class cmGeneratorTarget;
-class cmGlobalNinjaGenerator;
+class cmLocalGenerator;
class cmOutputConverter;
class cmStateDirectory;
@@ -27,6 +27,8 @@ public:
cmLinkLineDeviceComputer& operator=(cmLinkLineDeviceComputer const&) =
delete;
+ bool ComputeRequiresDeviceLinking(cmComputeLinkInformation& cli);
+
std::string ComputeLinkLibraries(cmComputeLinkInformation& cli,
std::string const& stdLibString) override;
@@ -34,21 +36,7 @@ public:
std::string const& config) override;
};
-class cmNinjaLinkLineDeviceComputer : public cmLinkLineDeviceComputer
-{
-public:
- cmNinjaLinkLineDeviceComputer(cmOutputConverter* outputConverter,
- cmStateDirectory const& stateDir,
- cmGlobalNinjaGenerator const* gg);
-
- cmNinjaLinkLineDeviceComputer(cmNinjaLinkLineDeviceComputer const&) = delete;
- cmNinjaLinkLineDeviceComputer& operator=(
- cmNinjaLinkLineDeviceComputer const&) = delete;
-
- std::string ConvertToLinkReference(std::string const& input) const override;
-
-private:
- cmGlobalNinjaGenerator const* GG;
-};
+bool requireDeviceLinking(cmGeneratorTarget& target, cmLocalGenerator& lg,
+ const std::string& config);
#endif
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx
index 297babfd8..1b01ea202 100644
--- a/Source/cmListCommand.cxx
+++ b/Source/cmListCommand.cxx
@@ -19,6 +19,7 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmStringReplaceHelper.h"
#include "cmSystemTools.h"
@@ -42,6 +43,15 @@ bool cmListCommand::InitialPass(std::vector<std::string> const& args,
if (subCommand == "APPEND") {
return this->HandleAppendCommand(args);
}
+ if (subCommand == "PREPEND") {
+ return this->HandlePrependCommand(args);
+ }
+ if (subCommand == "POP_BACK") {
+ return this->HandlePopBackCommand(args);
+ }
+ if (subCommand == "POP_FRONT") {
+ return this->HandlePopFrontCommand(args);
+ }
if (subCommand == "FIND") {
return this->HandleFindCommand(args);
}
@@ -222,20 +232,141 @@ bool cmListCommand::HandleAppendCommand(std::vector<std::string> const& args)
return true;
}
- const std::string& listName = args[1];
+ std::string const& listName = args[1];
// expand the variable
std::string listString;
this->GetListString(listString, listName);
- if (!listString.empty() && !args.empty()) {
- listString += ";";
+ // If `listString` or `args` is empty, no need to append `;`,
+ // then index is going to be `1` and points to the end-of-string ";"
+ auto const offset =
+ std::string::size_type(listString.empty() || args.empty());
+ listString += &";"[offset] + cmJoin(cmMakeRange(args).advance(2), ";");
+
+ this->Makefile->AddDefinition(listName, listString.c_str());
+ return true;
+}
+
+bool cmListCommand::HandlePrependCommand(std::vector<std::string> const& args)
+{
+ assert(args.size() >= 2);
+
+ // Skip if nothing to prepend.
+ if (args.size() < 3) {
+ return true;
}
- listString += cmJoin(cmMakeRange(args).advance(2), ";");
+
+ std::string const& listName = args[1];
+ // expand the variable
+ std::string listString;
+ this->GetListString(listString, listName);
+
+ // If `listString` or `args` is empty, no need to append `;`,
+ // then `offset` is going to be `1` and points to the end-of-string ";"
+ auto const offset =
+ std::string::size_type(listString.empty() || args.empty());
+ listString.insert(0,
+ cmJoin(cmMakeRange(args).advance(2), ";") + &";"[offset]);
this->Makefile->AddDefinition(listName, listString.c_str());
return true;
}
+bool cmListCommand::HandlePopBackCommand(std::vector<std::string> const& args)
+{
+ assert(args.size() >= 2);
+
+ auto ai = args.cbegin();
+ ++ai; // Skip subcommand name
+ std::string const& listName = *ai++;
+ std::vector<std::string> varArgsExpanded;
+ if (!this->GetList(varArgsExpanded, listName)) {
+ // Can't get the list definition... undefine any vars given after.
+ for (; ai != args.cend(); ++ai) {
+ this->Makefile->RemoveDefinition(*ai);
+ }
+ return true;
+ }
+
+ if (!varArgsExpanded.empty()) {
+ if (ai == args.cend()) {
+ // No variables are given... Just remove one element.
+ varArgsExpanded.pop_back();
+ } else {
+ // Ok, assign elements to be removed to the given variables
+ for (; !varArgsExpanded.empty() && ai != args.cend(); ++ai) {
+ assert(!ai->empty());
+ this->Makefile->AddDefinition(*ai, varArgsExpanded.back().c_str());
+ varArgsExpanded.pop_back();
+ }
+ // Undefine the rest variables if the list gets empty earlier...
+ for (; ai != args.cend(); ++ai) {
+ this->Makefile->RemoveDefinition(*ai);
+ }
+ }
+
+ this->Makefile->AddDefinition(listName,
+ cmJoin(varArgsExpanded, ";").c_str());
+
+ } else if (ai !=
+ args.cend()) { // The list is empty, but some args were given
+ // Need to *undefine* 'em all, cuz there are no items to assign...
+ for (; ai != args.cend(); ++ai) {
+ this->Makefile->RemoveDefinition(*ai);
+ }
+ }
+
+ return true;
+}
+
+bool cmListCommand::HandlePopFrontCommand(std::vector<std::string> const& args)
+{
+ assert(args.size() >= 2);
+
+ auto ai = args.cbegin();
+ ++ai; // Skip subcommand name
+ std::string const& listName = *ai++;
+ std::vector<std::string> varArgsExpanded;
+ if (!this->GetList(varArgsExpanded, listName)) {
+ // Can't get the list definition... undefine any vars given after.
+ for (; ai != args.cend(); ++ai) {
+ this->Makefile->RemoveDefinition(*ai);
+ }
+ return true;
+ }
+
+ if (!varArgsExpanded.empty()) {
+ if (ai == args.cend()) {
+ // No variables are given... Just remove one element.
+ varArgsExpanded.erase(varArgsExpanded.begin());
+ } else {
+ // Ok, assign elements to be removed to the given variables
+ auto vi = varArgsExpanded.begin();
+ for (; vi != varArgsExpanded.end() && ai != args.cend(); ++ai, ++vi) {
+ assert(!ai->empty());
+ this->Makefile->AddDefinition(*ai, vi->c_str());
+ }
+ varArgsExpanded.erase(varArgsExpanded.begin(), vi);
+ // Undefine the rest variables if the list gets empty earlier...
+ for (; ai != args.cend(); ++ai) {
+ this->Makefile->RemoveDefinition(*ai);
+ }
+ }
+
+ this->Makefile->AddDefinition(listName,
+ cmJoin(varArgsExpanded, ";").c_str());
+
+ } else if (ai !=
+ args.cend()) { // The list is empty, but some args were given
+ // Need to *undefine* 'em all, cuz there are no items to assign...
+ for (; ai != args.cend(); ++ai) {
+ this->Makefile->RemoveDefinition(*ai);
+ }
+ }
+
+ return true;
+}
+
bool cmListCommand::HandleFindCommand(std::vector<std::string> const& args)
{
if (args.size() != 4) {
diff --git a/Source/cmListCommand.h b/Source/cmListCommand.h
index 76a985657..ea3d64399 100644
--- a/Source/cmListCommand.h
+++ b/Source/cmListCommand.h
@@ -35,6 +35,9 @@ protected:
bool HandleLengthCommand(std::vector<std::string> const& args);
bool HandleGetCommand(std::vector<std::string> const& args);
bool HandleAppendCommand(std::vector<std::string> const& args);
+ bool HandlePrependCommand(std::vector<std::string> const& args);
+ bool HandlePopBackCommand(std::vector<std::string> const& args);
+ bool HandlePopFrontCommand(std::vector<std::string> const& args);
bool HandleFindCommand(std::vector<std::string> const& args);
bool HandleInsertCommand(std::vector<std::string> const& args);
bool HandleJoinCommand(std::vector<std::string> const& args);
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index f85511964..df0d00c59 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -27,6 +27,8 @@ struct cmListFileParser
cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt,
cmMessenger* messenger, const char* filename);
~cmListFileParser();
+ cmListFileParser(const cmListFileParser&) = delete;
+ cmListFileParser& operator=(const cmListFileParser&) = delete;
void IssueFileOpenError(std::string const& text) const;
void IssueError(std::string const& text) const;
bool ParseFile();
@@ -190,12 +192,9 @@ bool cmListFileParser::ParseFunction(const char* name, long line)
}
// Arguments.
- unsigned long lastLine;
unsigned long parenDepth = 0;
this->Separation = SeparationOkay;
- while (
- (static_cast<void>(lastLine = cmListFileLexer_GetCurrentLine(this->Lexer)),
- token = cmListFileLexer_Scan(this->Lexer))) {
+ while ((token = cmListFileLexer_Scan(this->Lexer))) {
if (token->type == cmListFileLexer_Token_Space ||
token->type == cmListFileLexer_Token_Newline) {
this->Separation = SeparationOkay;
@@ -250,7 +249,7 @@ bool cmListFileParser::ParseFunction(const char* name, long line)
std::ostringstream error;
cmListFileContext lfc;
lfc.FilePath = this->FileName;
- lfc.Line = lastLine;
+ lfc.Line = line;
cmListFileBacktrace lfbt = this->Backtrace;
lfbt = lfbt.Push(lfc);
error << "Parse error. Function missing ending \")\". "
diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx
index cd715188a..69751b62b 100644
--- a/Source/cmLoadCommandCommand.cxx
+++ b/Source/cmLoadCommandCommand.cxx
@@ -33,7 +33,7 @@ public:
this->info.CAPI = &cmStaticCAPI;
}
- ///! clean up any memory allocated by the plugin
+ //! clean up any memory allocated by the plugin
~cmLoadedCommand() override;
/**
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index f6962d160..fe5c8afe1 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -6,6 +6,7 @@
#include "cmComputeLinkInformation.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
#include "cmGeneratorExpressionEvaluationFile.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
@@ -34,6 +35,7 @@
#include "cmsys/RegularExpression.hxx"
#include <algorithm>
#include <assert.h>
+#include <initializer_list>
#include <iterator>
#include <sstream>
#include <stdio.h>
@@ -51,25 +53,23 @@
// replaced in the form <var> with GetSafeDefinition(var).
// ${LANG} is replaced in the variable first with all enabled
// languages.
-static const char* ruleReplaceVars[] = {
- "CMAKE_${LANG}_COMPILER",
- "CMAKE_SHARED_LIBRARY_CREATE_${LANG}_FLAGS",
- "CMAKE_SHARED_MODULE_CREATE_${LANG}_FLAGS",
- "CMAKE_SHARED_MODULE_${LANG}_FLAGS",
- "CMAKE_SHARED_LIBRARY_${LANG}_FLAGS",
- "CMAKE_${LANG}_LINK_FLAGS",
- "CMAKE_SHARED_LIBRARY_SONAME_${LANG}_FLAG",
- "CMAKE_${LANG}_ARCHIVE",
- "CMAKE_AR",
- "CMAKE_CURRENT_SOURCE_DIR",
- "CMAKE_CURRENT_BINARY_DIR",
- "CMAKE_RANLIB",
- "CMAKE_LINKER",
- "CMAKE_MT",
- "CMAKE_CUDA_HOST_COMPILER",
- "CMAKE_CUDA_HOST_LINK_LAUNCHER",
- "CMAKE_CL_SHOWINCLUDES_PREFIX"
-};
+static auto ruleReplaceVars = { "CMAKE_${LANG}_COMPILER",
+ "CMAKE_SHARED_LIBRARY_CREATE_${LANG}_FLAGS",
+ "CMAKE_SHARED_MODULE_CREATE_${LANG}_FLAGS",
+ "CMAKE_SHARED_MODULE_${LANG}_FLAGS",
+ "CMAKE_SHARED_LIBRARY_${LANG}_FLAGS",
+ "CMAKE_${LANG}_LINK_FLAGS",
+ "CMAKE_SHARED_LIBRARY_SONAME_${LANG}_FLAG",
+ "CMAKE_${LANG}_ARCHIVE",
+ "CMAKE_AR",
+ "CMAKE_CURRENT_SOURCE_DIR",
+ "CMAKE_CURRENT_BINARY_DIR",
+ "CMAKE_RANLIB",
+ "CMAKE_LINKER",
+ "CMAKE_MT",
+ "CMAKE_CUDA_HOST_COMPILER",
+ "CMAKE_CUDA_HOST_LINK_LAUNCHER",
+ "CMAKE_CL_SHOWINCLUDES_PREFIX" };
cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
: cmOutputConverter(makefile->GetStateSnapshot())
@@ -151,15 +151,13 @@ cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
this->VariableMappings[compilerOptionSysroot] =
this->Makefile->GetSafeDefinition(compilerOptionSysroot);
- for (const char* const* replaceIter = cm::cbegin(ruleReplaceVars);
- replaceIter != cm::cend(ruleReplaceVars); ++replaceIter) {
- std::string actualReplace = *replaceIter;
- if (actualReplace.find("${LANG}") != std::string::npos) {
- cmSystemTools::ReplaceString(actualReplace, "${LANG}", lang);
+ for (std::string replaceVar : ruleReplaceVars) {
+ if (replaceVar.find("${LANG}") != std::string::npos) {
+ cmSystemTools::ReplaceString(replaceVar, "${LANG}", lang);
}
- this->VariableMappings[actualReplace] =
- this->Makefile->GetSafeDefinition(actualReplace);
+ this->VariableMappings[replaceVar] =
+ this->Makefile->GetSafeDefinition(replaceVar);
}
}
}
@@ -366,9 +364,8 @@ void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config)
void cmLocalGenerator::ProcessEvaluationFiles(
std::vector<std::string>& generatedFiles)
{
- std::vector<cmGeneratorExpressionEvaluationFile*> ef =
- this->Makefile->GetEvaluationFiles();
- for (cmGeneratorExpressionEvaluationFile* geef : ef) {
+ for (cmGeneratorExpressionEvaluationFile* geef :
+ this->Makefile->GetEvaluationFiles()) {
geef->Generate(this);
if (cmSystemTools::GetFatalErrorOccured()) {
return;
@@ -382,15 +379,15 @@ void cmLocalGenerator::ProcessEvaluationFiles(
std::back_inserter(intersection));
if (!intersection.empty()) {
cmSystemTools::Error("Files to be generated by multiple different "
- "commands: ",
- cmWrap('"', intersection, '"', " ").c_str());
+ "commands: " +
+ cmWrap('"', intersection, '"', " "));
return;
}
- generatedFiles.insert(generatedFiles.end(), files.begin(), files.end());
- std::vector<std::string>::iterator newIt =
- generatedFiles.end() - files.size();
- std::inplace_merge(generatedFiles.begin(), newIt, generatedFiles.end());
+ cmAppend(generatedFiles, files);
+ std::inplace_merge(generatedFiles.begin(),
+ generatedFiles.end() - files.size(),
+ generatedFiles.end());
}
}
@@ -473,7 +470,7 @@ void cmLocalGenerator::GenerateInstallRules()
<< "if(NOT DEFINED CMAKE_INSTALL_PREFIX)" << std::endl
<< " set(CMAKE_INSTALL_PREFIX \"" << prefix << "\")" << std::endl
<< "endif()" << std::endl
- << "string(REGEX REPLACE \"/$\" \"\" CMAKE_INSTALL_PREFIX "
+ << R"(string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX )"
<< "\"${CMAKE_INSTALL_PREFIX}\")" << std::endl
<< std::endl;
@@ -792,7 +789,7 @@ std::string cmLocalGenerator::GetIncludeFlags(
#endif
for (std::string const& i : includes) {
if (fwSearchFlag && *fwSearchFlag && this->Makefile->IsOn("APPLE") &&
- cmSystemTools::IsPathToFramework(i.c_str())) {
+ cmSystemTools::IsPathToFramework(i)) {
std::string frameworkDir = i;
frameworkDir += "/../";
frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
@@ -892,6 +889,32 @@ void cmLocalGenerator::AddCompileOptions(std::string& flags,
}
}
this->AddCompilerRequirementFlag(flags, target, lang);
+
+ // Add compile flag for the MSVC compiler only.
+ cmMakefile* mf = this->GetMakefile();
+ if (const char* jmc =
+ mf->GetDefinition("CMAKE_" + lang + "_COMPILE_OPTIONS_JMC")) {
+
+ // Handle Just My Code debugging flags, /JMC.
+ // If the target is a Managed C++ one, /JMC is not compatible.
+ if (target->GetManagedType(config) !=
+ cmGeneratorTarget::ManagedType::Managed) {
+ // add /JMC flags if target property VS_JUST_MY_CODE_DEBUGGING is set
+ // to ON
+ if (char const* jmcExprGen =
+ target->GetProperty("VS_JUST_MY_CODE_DEBUGGING")) {
+ cmGeneratorExpression ge;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(jmcExprGen);
+ std::string isJMCEnabled = cge->Evaluate(this, config);
+ if (cmSystemTools::IsOn(isJMCEnabled)) {
+ std::vector<std::string> optVec;
+ cmSystemTools::ExpandListArgument(jmc, optVec);
+ this->AppendCompileOptions(flags, optVec);
+ }
+ }
+ }
+ }
}
std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit(
@@ -1146,30 +1169,34 @@ void cmLocalGenerator::GetTargetFlags(
libraryLinkVariable = "CMAKE_MODULE_LINKER_FLAGS";
CM_FALLTHROUGH;
case cmStateEnums::SHARED_LIBRARY: {
- linkFlags = this->Makefile->GetSafeDefinition(libraryLinkVariable);
- linkFlags += " ";
- if (!buildType.empty()) {
- std::string build = libraryLinkVariable;
- build += "_";
- build += buildType;
- linkFlags += this->Makefile->GetSafeDefinition(build);
+ if (linkLanguage != "Swift") {
+ linkFlags = this->Makefile->GetSafeDefinition(libraryLinkVariable);
linkFlags += " ";
- }
- if (this->Makefile->IsOn("WIN32") &&
- !(this->Makefile->IsOn("CYGWIN") || this->Makefile->IsOn("MINGW"))) {
- std::vector<cmSourceFile*> sources;
- target->GetSourceFiles(sources, buildType);
- std::string defFlag =
- this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG");
- for (cmSourceFile* sf : sources) {
- if (sf->GetExtension() == "def") {
- linkFlags += defFlag;
- linkFlags += this->ConvertToOutputFormat(
- cmSystemTools::CollapseFullPath(sf->GetFullPath()), SHELL);
- linkFlags += " ";
+ if (!buildType.empty()) {
+ std::string build = libraryLinkVariable;
+ build += "_";
+ build += buildType;
+ linkFlags += this->Makefile->GetSafeDefinition(build);
+ linkFlags += " ";
+ }
+ if (this->Makefile->IsOn("WIN32") &&
+ !(this->Makefile->IsOn("CYGWIN") ||
+ this->Makefile->IsOn("MINGW"))) {
+ std::vector<cmSourceFile*> sources;
+ target->GetSourceFiles(sources, buildType);
+ std::string defFlag =
+ this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG");
+ for (cmSourceFile* sf : sources) {
+ if (sf->GetExtension() == "def") {
+ linkFlags += defFlag;
+ linkFlags += this->ConvertToOutputFormat(
+ cmSystemTools::CollapseFullPath(sf->GetFullPath()), SHELL);
+ linkFlags += " ";
+ }
}
}
}
+
const char* targetLinkFlags = target->GetProperty("LINK_FLAGS");
if (targetLinkFlags) {
linkFlags += targetLinkFlags;
@@ -1184,6 +1211,7 @@ void cmLocalGenerator::GetTargetFlags(
linkFlags += " ";
}
}
+
std::vector<std::string> opts;
target->GetLinkOptions(opts, config, linkLanguage);
// LINK_OPTIONS are escaped.
@@ -1194,25 +1222,49 @@ void cmLocalGenerator::GetTargetFlags(
}
} break;
case cmStateEnums::EXECUTABLE: {
- linkFlags += this->Makefile->GetSafeDefinition("CMAKE_EXE_LINKER_FLAGS");
- linkFlags += " ";
- if (!buildType.empty()) {
- std::string build = "CMAKE_EXE_LINKER_FLAGS_";
- build += buildType;
- linkFlags += this->Makefile->GetSafeDefinition(build);
+ if (linkLanguage != "Swift") {
+ linkFlags +=
+ this->Makefile->GetSafeDefinition("CMAKE_EXE_LINKER_FLAGS");
linkFlags += " ";
+ if (!buildType.empty()) {
+ std::string build = "CMAKE_EXE_LINKER_FLAGS_";
+ build += buildType;
+ linkFlags += this->Makefile->GetSafeDefinition(build);
+ linkFlags += " ";
+ }
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error(
+ "CMake can not determine linker language for target: " +
+ target->GetName());
+ return;
+ }
+
+ if (target->GetPropertyAsBool("WIN32_EXECUTABLE")) {
+ linkFlags +=
+ this->Makefile->GetSafeDefinition("CMAKE_CREATE_WIN32_EXE");
+ linkFlags += " ";
+ } else {
+ linkFlags +=
+ this->Makefile->GetSafeDefinition("CMAKE_CREATE_CONSOLE_EXE");
+ linkFlags += " ";
+ }
+
+ if (target->IsExecutableWithExports()) {
+ std::string exportFlagVar = "CMAKE_EXE_EXPORTS_";
+ exportFlagVar += linkLanguage;
+ exportFlagVar += "_FLAG";
+
+ linkFlags += this->Makefile->GetSafeDefinition(exportFlagVar);
+ linkFlags += " ";
+ }
}
- if (linkLanguage.empty()) {
- cmSystemTools::Error(
- "CMake can not determine linker language for target: ",
- target->GetName().c_str());
- return;
- }
+
this->AddLanguageFlagsForLinking(flags, target, linkLanguage, buildType);
if (pcli) {
this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
frameworkPath, linkPath);
}
+
if (cmSystemTools::IsOn(
this->Makefile->GetDefinition("BUILD_SHARED_LIBS"))) {
std::string sFlagVar = std::string("CMAKE_SHARED_BUILD_") +
@@ -1220,23 +1272,6 @@ void cmLocalGenerator::GetTargetFlags(
linkFlags += this->Makefile->GetSafeDefinition(sFlagVar);
linkFlags += " ";
}
- if (target->GetPropertyAsBool("WIN32_EXECUTABLE")) {
- linkFlags +=
- this->Makefile->GetSafeDefinition("CMAKE_CREATE_WIN32_EXE");
- linkFlags += " ";
- } else {
- linkFlags +=
- this->Makefile->GetSafeDefinition("CMAKE_CREATE_CONSOLE_EXE");
- linkFlags += " ";
- }
- if (target->IsExecutableWithExports()) {
- std::string exportFlagVar = "CMAKE_EXE_EXPORTS_";
- exportFlagVar += linkLanguage;
- exportFlagVar += "_FLAG";
-
- linkFlags += this->Makefile->GetSafeDefinition(exportFlagVar);
- linkFlags += " ";
- }
std::string cmp0065Flags =
this->GetLinkLibsCMP0065(linkLanguage, *target);
@@ -1259,6 +1294,7 @@ void cmLocalGenerator::GetTargetFlags(
linkFlags += " ";
}
}
+
std::vector<std::string> opts;
target->GetLinkOptions(opts, config, linkLanguage);
// LINK_OPTIONS are escaped.
@@ -1283,6 +1319,10 @@ void cmLocalGenerator::GetTargetCompileFlags(cmGeneratorTarget* target,
// Add language-specific flags.
this->AddLanguageFlags(flags, target, lang, config);
+ if (target->IsIPOEnabled(lang, config)) {
+ this->AppendFeatureOptions(flags, lang, "IPO");
+ }
+
this->AddArchitectureFlags(flags, target, lang, config);
if (lang == "Fortran") {
@@ -1404,9 +1444,9 @@ void cmLocalGenerator::OutputLinkLibraries(
std::string linkLanguage = cli.GetLinkLanguage();
- std::string libPathFlag =
+ const std::string& libPathFlag =
this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG");
- std::string libPathTerminator =
+ const std::string& libPathTerminator =
this->Makefile->GetSafeDefinition("CMAKE_LIBRARY_PATH_TERMINATOR");
// Add standard libraries for this language.
@@ -1540,8 +1580,39 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
flagsVar += "_FLAGS";
this->AddConfigVariableFlags(flags, flagsVar, config);
- if (target->IsIPOEnabled(lang, config)) {
- this->AppendFeatureOptions(flags, lang, "IPO");
+ // Add MSVC runtime library flags. This is activated by the presence
+ // of a default selection whether or not it is overridden by a property.
+ const char* msvcRuntimeLibraryDefault =
+ this->Makefile->GetDefinition("CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT");
+ if (msvcRuntimeLibraryDefault && *msvcRuntimeLibraryDefault) {
+ const char* msvcRuntimeLibraryValue =
+ target->GetProperty("MSVC_RUNTIME_LIBRARY");
+ if (!msvcRuntimeLibraryValue) {
+ msvcRuntimeLibraryValue = msvcRuntimeLibraryDefault;
+ }
+ cmGeneratorExpression ge;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(msvcRuntimeLibraryValue);
+ std::string const msvcRuntimeLibrary =
+ cge->Evaluate(this, config, false, target);
+ if (!msvcRuntimeLibrary.empty()) {
+ if (const char* msvcRuntimeLibraryOptions =
+ this->Makefile->GetDefinition(
+ "CMAKE_" + lang + "_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_" +
+ msvcRuntimeLibrary)) {
+ this->AppendCompileOptions(flags, msvcRuntimeLibraryOptions);
+ } else if ((this->Makefile->GetSafeDefinition(
+ "CMAKE_" + lang + "_COMPILER_ID") == "MSVC" ||
+ this->Makefile->GetSafeDefinition(
+ "CMAKE_" + lang + "_SIMULATE_ID") == "MSVC") &&
+ !cmSystemTools::GetErrorOccuredFlag()) {
+ // The compiler uses the MSVC ABI so it needs a known runtime library.
+ this->IssueMessage(MessageType::FATAL_ERROR,
+ "MSVC_RUNTIME_LIBRARY value '" +
+ msvcRuntimeLibrary + "' not known for this " +
+ lang + " compiler.");
+ }
+ }
}
}
@@ -1559,6 +1630,10 @@ void cmLocalGenerator::AddLanguageFlagsForLinking(
}
this->AddLanguageFlags(flags, target, lang, config);
+
+ if (target->IsIPOEnabled(lang, config)) {
+ this->AppendFeatureOptions(flags, lang, "IPO");
+ }
}
cmGeneratorTarget* cmLocalGenerator::FindGeneratorTargetToUse(
@@ -1852,7 +1927,9 @@ static void AddVisibilityCompileOption(std::string& flags,
strcmp(prop, "protected") != 0 && strcmp(prop, "internal") != 0) {
std::ostringstream e;
e << "Target " << target->GetName() << " uses unsupported value \"" << prop
- << "\" for " << flagDefine << ".";
+ << "\" for " << flagDefine << "."
+ << " The supported values are: default, hidden, protected, and "
+ "internal.";
cmSystemTools::Error(e.str());
return;
}
@@ -2263,11 +2340,8 @@ void cmLocalGenerator::JoinDefines(const std::set<std::string>& defines,
dflag = df;
}
}
-
- std::set<std::string>::const_iterator defineIt = defines.begin();
- const std::set<std::string>::const_iterator defineEnd = defines.end();
const char* itemSeparator = definesString.empty() ? "" : " ";
- for (; defineIt != defineEnd; ++defineIt) {
+ for (std::string const& define : defines) {
// Append the definition with proper escaping.
std::string def = dflag;
if (this->GetState()->UseWatcomWMake()) {
@@ -2281,7 +2355,7 @@ void cmLocalGenerator::JoinDefines(const std::set<std::string>& defines,
// command line without any escapes. However we still have to
// get the '$' and '#' characters through WMake as '$$' and
// '$#'.
- for (const char* c = defineIt->c_str(); *c; ++c) {
+ for (const char* c = define.c_str(); *c; ++c) {
if (*c == '$' || *c == '#') {
def += '$';
}
@@ -2290,11 +2364,11 @@ void cmLocalGenerator::JoinDefines(const std::set<std::string>& defines,
} else {
// Make the definition appear properly on the command line. Use
// -DNAME="value" instead of -D"NAME=value" for historical reasons.
- std::string::size_type eq = defineIt->find("=");
- def += defineIt->substr(0, eq);
+ std::string::size_type eq = define.find('=');
+ def += define.substr(0, eq);
if (eq != std::string::npos) {
def += "=";
- def += this->EscapeForShell(defineIt->c_str() + eq + 1, true);
+ def += this->EscapeForShell(define.substr(eq + 1), true);
}
}
definesString += itemSeparator;
@@ -2851,7 +2925,7 @@ static void cmLGInfoProp(cmMakefile* mf, cmGeneratorTarget* target,
void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target,
const std::string& targetName,
- const char* fname)
+ const std::string& fname)
{
// Find the Info.plist template.
const char* in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST");
@@ -2885,11 +2959,12 @@ void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target,
cmLGInfoProp(mf, target, "MACOSX_BUNDLE_SHORT_VERSION_STRING");
cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_VERSION");
cmLGInfoProp(mf, target, "MACOSX_BUNDLE_COPYRIGHT");
- mf->ConfigureFile(inFile.c_str(), fname, false, false, false);
+ mf->ConfigureFile(inFile, fname, false, false, false);
}
void cmLocalGenerator::GenerateFrameworkInfoPList(
- cmGeneratorTarget* target, const std::string& targetName, const char* fname)
+ cmGeneratorTarget* target, const std::string& targetName,
+ const std::string& fname)
{
// Find the Info.plist template.
const char* in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST");
@@ -2919,5 +2994,5 @@ void cmLocalGenerator::GenerateFrameworkInfoPList(
cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_IDENTIFIER");
cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_SHORT_VERSION_STRING");
cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_VERSION");
- mf->ConfigureFile(inFile.c_str(), fname, false, false, false);
+ mf->ConfigureFile(inFile, fname, false, false, false);
}
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 9521ec5b8..f0c6806fb 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -76,13 +76,13 @@ public:
bool IsRootMakefile() const;
- ///! Get the makefile for this generator
+ //! Get the makefile for this generator
cmMakefile* GetMakefile() { return this->Makefile; }
- ///! Get the makefile for this generator, const version
+ //! Get the makefile for this generator, const version
const cmMakefile* GetMakefile() const { return this->Makefile; }
- ///! Get the GlobalGenerator this is associated with
+ //! Get the GlobalGenerator this is associated with
cmGlobalGenerator* GetGlobalGenerator() { return this->GlobalGenerator; }
const cmGlobalGenerator* GetGlobalGenerator() const
{
@@ -118,7 +118,7 @@ public:
void AddCompilerRequirementFlag(std::string& flags,
cmGeneratorTarget const* target,
const std::string& lang);
- ///! Append flags to a string.
+ //! Append flags to a string.
virtual void AppendFlags(std::string& flags,
const std::string& newFlags) const;
virtual void AppendFlags(std::string& flags, const char* newFlags) const;
@@ -131,7 +131,7 @@ public:
cmGeneratorTarget* target,
const std::string& config,
const std::string& lang);
- ///! Get the include flags for the current makefile and language
+ //! Get the include flags for the current makefile and language
std::string GetIncludeFlags(const std::vector<std::string>& includes,
cmGeneratorTarget* target,
const std::string& lang,
@@ -340,14 +340,14 @@ public:
*/
void GenerateAppleInfoPList(cmGeneratorTarget* target,
const std::string& targetName,
- const char* fname);
+ const std::string& fname);
/**
* Generate a macOS framework Info.plist file.
*/
void GenerateFrameworkInfoPList(cmGeneratorTarget* target,
const std::string& targetName,
- const char* fname);
+ const std::string& fname);
/** Construct a comment for a custom command. */
std::string ConstructComment(cmCustomCommandGenerator const& ccg,
const char* default_comment = "");
@@ -403,7 +403,7 @@ public:
const std::string& prop);
protected:
- ///! put all the libraries for a target on into the given stream
+ //! put all the libraries for a target on into the given stream
void OutputLinkLibraries(cmComputeLinkInformation* pcli,
cmLinkLineComputer* linkLineComputer,
std::string& linkLibraries,
diff --git a/Source/cmLocalGhsMultiGenerator.cxx b/Source/cmLocalGhsMultiGenerator.cxx
index 125e8b530..bf25f98ea 100644
--- a/Source/cmLocalGhsMultiGenerator.cxx
+++ b/Source/cmLocalGhsMultiGenerator.cxx
@@ -2,12 +2,15 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmLocalGhsMultiGenerator.h"
-#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGhsMultiTargetGenerator.h"
-#include "cmGlobalGhsMultiGenerator.h"
-#include "cmMakefile.h"
+#include "cmGlobalGenerator.h"
#include "cmSourceFile.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
+
+#include <algorithm>
+#include <utility>
cmLocalGhsMultiGenerator::cmLocalGhsMultiGenerator(cmGlobalGenerator* gg,
cmMakefile* mf)
@@ -15,9 +18,7 @@ cmLocalGhsMultiGenerator::cmLocalGhsMultiGenerator(cmGlobalGenerator* gg,
{
}
-cmLocalGhsMultiGenerator::~cmLocalGhsMultiGenerator()
-{
-}
+cmLocalGhsMultiGenerator::~cmLocalGhsMultiGenerator() = default;
std::string cmLocalGhsMultiGenerator::GetTargetDirectory(
cmGeneratorTarget const* target) const
diff --git a/Source/cmLocalGhsMultiGenerator.h b/Source/cmLocalGhsMultiGenerator.h
index d5bec4200..b6ccd0815 100644
--- a/Source/cmLocalGhsMultiGenerator.h
+++ b/Source/cmLocalGhsMultiGenerator.h
@@ -5,7 +5,14 @@
#include "cmLocalGenerator.h"
-class cmGeneratedFileStream;
+#include <map>
+#include <string>
+#include <vector>
+
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmMakefile;
+class cmSourceFile;
/** \class cmLocalGhsMultiGenerator
* \brief Write Green Hills MULTI project files.
@@ -18,12 +25,12 @@ class cmLocalGhsMultiGenerator : public cmLocalGenerator
public:
cmLocalGhsMultiGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
- virtual ~cmLocalGhsMultiGenerator();
+ ~cmLocalGhsMultiGenerator() override;
/**
* Generate the makefile for this directory.
*/
- virtual void Generate();
+ void Generate() override;
std::string GetTargetDirectory(
cmGeneratorTarget const* target) const override;
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 69656a286..81cafa321 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -14,6 +14,7 @@
#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalNinjaGenerator.h"
@@ -69,7 +70,7 @@ void cmLocalNinjaGenerator::Generate()
this->WritePools(this->GetRulesFileStream());
- const std::string showIncludesPrefix =
+ const std::string& showIncludesPrefix =
this->GetMakefile()->GetSafeDefinition("CMAKE_CL_SHOWINCLUDES_PREFIX");
if (!showIncludesPrefix.empty()) {
cmGlobalNinjaGenerator::WriteComment(this->GetRulesFileStream(),
@@ -79,25 +80,22 @@ void cmLocalNinjaGenerator::Generate()
}
}
- const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
- for (cmGeneratorTarget* target : targets) {
+ for (cmGeneratorTarget* target : this->GetGeneratorTargets()) {
if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
- cmNinjaTargetGenerator* tg = cmNinjaTargetGenerator::New(target);
+ auto tg = cmNinjaTargetGenerator::New(target);
if (tg) {
tg->Generate();
// Add the target to "all" if required.
- if (!this->GetGlobalNinjaGenerator()->IsExcluded(
- this->GetGlobalNinjaGenerator()->GetLocalGenerators()[0],
- target)) {
+ if (!this->GetGlobalNinjaGenerator()->IsExcluded(target)) {
this->GetGlobalNinjaGenerator()->AddDependencyToAll(target);
}
- delete tg;
}
}
this->WriteCustomCommandBuildStatements();
+ this->AdditionalCleanFiles();
}
// TODO: Picked up from cmLocalUnixMakefileGenerator3. Refactor it.
@@ -234,8 +232,8 @@ void cmLocalNinjaGenerator::WritePools(std::ostream& os)
os << " depth = " << jobs << std::endl;
os << std::endl;
} else {
- cmSystemTools::Error("Invalid pool defined by property 'JOB_POOLS': ",
- pool.c_str());
+ cmSystemTools::Error("Invalid pool defined by property 'JOB_POOLS': " +
+ pool);
}
}
}
@@ -285,8 +283,7 @@ void cmLocalNinjaGenerator::AppendTargetDepends(cmGeneratorTarget* target,
void cmLocalNinjaGenerator::AppendCustomCommandDeps(
cmCustomCommandGenerator const& ccg, cmNinjaDeps& ninjaDeps)
{
- const std::vector<std::string>& deps = ccg.GetDepends();
- for (std::string const& i : deps) {
+ for (std::string const& i : ccg.GetDepends()) {
std::string dep;
if (this->GetRealDependency(i, this->GetConfigName(), dep)) {
ninjaDeps.push_back(
@@ -457,7 +454,8 @@ void cmLocalNinjaGenerator::AppendCustomCommandLines(
void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
cmCustomCommand const* cc, const cmNinjaDeps& orderOnlyDeps)
{
- if (this->GetGlobalNinjaGenerator()->SeenCustomCommand(cc)) {
+ cmGlobalNinjaGenerator* gg = this->GetGlobalNinjaGenerator();
+ if (gg->SeenCustomCommand(cc)) {
return;
}
@@ -465,13 +463,14 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
const std::vector<std::string>& outputs = ccg.GetOutputs();
const std::vector<std::string>& byproducts = ccg.GetByproducts();
- cmNinjaDeps ninjaOutputs(outputs.size() + byproducts.size()), ninjaDeps;
bool symbolic = false;
- for (std::vector<std::string>::const_iterator o = outputs.begin();
- !symbolic && o != outputs.end(); ++o) {
- if (cmSourceFile* sf = this->Makefile->GetSource(*o)) {
- symbolic = sf->GetPropertyAsBool("SYMBOLIC");
+ for (std::string const& output : outputs) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(output)) {
+ if (sf->GetPropertyAsBool("SYMBOLIC")) {
+ symbolic = true;
+ break;
+ }
}
}
@@ -480,25 +479,29 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
file of each imported target that has an add_dependencies pointing \
at us. How to know which ExternalProject step actually provides it?
#endif
+ cmNinjaDeps ninjaOutputs(outputs.size() + byproducts.size());
std::transform(outputs.begin(), outputs.end(), ninjaOutputs.begin(),
- this->GetGlobalNinjaGenerator()->MapToNinjaPath());
+ gg->MapToNinjaPath());
std::transform(byproducts.begin(), byproducts.end(),
- ninjaOutputs.begin() + outputs.size(),
- this->GetGlobalNinjaGenerator()->MapToNinjaPath());
- this->AppendCustomCommandDeps(ccg, ninjaDeps);
+ ninjaOutputs.begin() + outputs.size(), gg->MapToNinjaPath());
for (std::string const& ninjaOutput : ninjaOutputs) {
- this->GetGlobalNinjaGenerator()->SeenCustomCommandOutput(ninjaOutput);
+ gg->SeenCustomCommandOutput(ninjaOutput);
}
+ cmNinjaDeps ninjaDeps;
+ this->AppendCustomCommandDeps(ccg, ninjaDeps);
+
std::vector<std::string> cmdLines;
this->AppendCustomCommandLines(ccg, cmdLines);
if (cmdLines.empty()) {
- this->GetGlobalNinjaGenerator()->WritePhonyBuild(
- this->GetBuildFileStream(),
- "Phony custom command for " + ninjaOutputs[0], ninjaOutputs, ninjaDeps,
- cmNinjaDeps(), orderOnlyDeps, cmNinjaVars());
+ cmNinjaBuild build("phony");
+ build.Comment = "Phony custom command for " + ninjaOutputs[0];
+ build.Outputs = std::move(ninjaOutputs);
+ build.ExplicitDeps = std::move(ninjaDeps);
+ build.OrderOnlyDeps = orderOnlyDeps;
+ gg->WriteBuild(this->GetBuildFileStream(), build);
} else {
std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]);
// Hash full path to make unique.
@@ -506,10 +509,10 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7);
- this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild(
+ gg->WriteCustomCommandBuild(
this->BuildCommandLine(cmdLines, customStep),
this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0],
- cc->GetDepfile(), cc->GetUsesTerminal(),
+ cc->GetDepfile(), cc->GetJobPool(), cc->GetUsesTerminal(),
/*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, ninjaDeps,
orderOnlyDeps);
}
@@ -601,3 +604,26 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher(
return launcher;
}
+
+void cmLocalNinjaGenerator::AdditionalCleanFiles()
+{
+ if (const char* prop_value =
+ this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) {
+ std::vector<std::string> cleanFiles;
+ {
+ cmGeneratorExpression ge;
+ auto cge = ge.Parse(prop_value);
+ cmSystemTools::ExpandListArgument(
+ cge->Evaluate(this,
+ this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")),
+ cleanFiles);
+ }
+ std::string const& binaryDir = this->GetCurrentBinaryDirectory();
+ cmGlobalNinjaGenerator* gg = this->GetGlobalNinjaGenerator();
+ for (std::string const& cleanFile : cleanFiles) {
+ // Support relative paths
+ gg->AddAdditionalCleanFile(
+ cmSystemTools::CollapseFullPath(cleanFile, binaryDir));
+ }
+ }
+}
diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h
index f772fb0a7..3a30bbb7b 100644
--- a/Source/cmLocalNinjaGenerator.h
+++ b/Source/cmLocalNinjaGenerator.h
@@ -105,6 +105,8 @@ private:
std::string const& customStep,
cmGeneratorTarget const* target) const;
+ void AdditionalCleanFiles();
+
std::string HomeRelativeOutputPath;
typedef std::map<cmCustomCommand const*, std::set<cmGeneratorTarget*>>
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 7eb4a03d5..c392e9787 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -11,9 +11,11 @@
#include <utility>
#include "cmAlgorithms.h"
+#include "cmCustomCommand.h" // IWYU pragma: keep
#include "cmCustomCommandGenerator.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTimeCache.h"
#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalUnixMakefileGenerator3.h"
@@ -22,6 +24,7 @@
#include "cmMakefile.h"
#include "cmMakefileTargetGenerator.h"
#include "cmOutputConverter.h"
+#include "cmRange.h"
#include "cmRulePlaceholderExpander.h"
#include "cmSourceFile.h"
#include "cmState.h"
@@ -113,10 +116,9 @@ void cmLocalUnixMakefileGenerator3::Generate()
this->Makefile->IsOn("CMAKE_SKIP_ASSEMBLY_SOURCE_RULES");
// Generate the rule files for each target.
- const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
cmGlobalUnixMakefileGenerator3* gg =
static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
- for (cmGeneratorTarget* target : targets) {
+ for (cmGeneratorTarget* target : this->GetGeneratorTargets()) {
if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
@@ -152,8 +154,7 @@ void cmLocalUnixMakefileGenerator3::ComputeHomeRelativeOutputPath()
void cmLocalUnixMakefileGenerator3::GetLocalObjectFiles(
std::map<std::string, LocalObjectInfo>& localObjectFiles)
{
- const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
- for (cmGeneratorTarget* gt : targets) {
+ for (cmGeneratorTarget* gt : this->GetGeneratorTargets()) {
if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
@@ -351,9 +352,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalMakefileTargets(
// for each target we just provide a rule to cd up to the top and do a make
// on the target
- const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
std::string localName;
- for (cmGeneratorTarget* target : targets) {
+ for (cmGeneratorTarget* target : this->GetGeneratorTargets()) {
if ((target->GetType() == cmStateEnums::EXECUTABLE) ||
(target->GetType() == cmStateEnums::STATIC_LIBRARY) ||
(target->GetType() == cmStateEnums::SHARED_LIBRARY) ||
@@ -501,8 +501,11 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule(
{
// Make sure there is a target.
if (target.empty()) {
- cmSystemTools::Error("No target for WriteMakeRule! called with comment: ",
- comment);
+ std::string err("No target for WriteMakeRule! called with comment: ");
+ if (comment) {
+ err += comment;
+ }
+ cmSystemTools::Error(err);
return;
}
@@ -859,7 +862,7 @@ void cmLocalUnixMakefileGenerator3::AppendRuleDepends(
// Add a dependency on the rule file itself unless an option to skip
// it is specifically enabled by the user or project.
if (!this->Makefile->IsOn("CMAKE_SKIP_RULE_DEPENDENCY")) {
- depends.insert(depends.end(), ruleFiles.begin(), ruleFiles.end());
+ cmAppend(depends, ruleFiles);
}
}
@@ -1034,11 +1037,11 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand(
this->CreateCDCommand(commands1, dir, relative);
// push back the custom commands
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
}
void cmLocalUnixMakefileGenerator3::AppendCleanCommand(
- std::vector<std::string>& commands, const std::vector<std::string>& files,
+ std::vector<std::string>& commands, const std::set<std::string>& files,
cmGeneratorTarget* target, const char* filename)
{
std::string currentBinDir = this->GetCurrentBinaryDirectory();
@@ -1054,7 +1057,7 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand(
std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile);
cmsys::ofstream fout(cleanfilePath.c_str());
if (!fout) {
- cmSystemTools::Error("Could not create ", cleanfilePath.c_str());
+ cmSystemTools::Error("Could not create " + cleanfilePath);
}
if (!files.empty()) {
fout << "file(REMOVE_RECURSE\n";
@@ -1090,6 +1093,56 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand(
}
}
+void cmLocalUnixMakefileGenerator3::AppendDirectoryCleanCommand(
+ std::vector<std::string>& commands)
+{
+ std::vector<std::string> cleanFiles;
+ // Look for additional files registered for cleaning in this directory.
+ if (const char* prop_value =
+ this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) {
+ cmGeneratorExpression ge;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop_value);
+ cmSystemTools::ExpandListArgument(
+ cge->Evaluate(this,
+ this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")),
+ cleanFiles);
+ }
+ if (cleanFiles.empty()) {
+ return;
+ }
+
+ cmLocalGenerator* rootLG =
+ this->GetGlobalGenerator()->GetLocalGenerators().at(0);
+ std::string const& binaryDir = rootLG->GetCurrentBinaryDirectory();
+ std::string const& currentBinaryDir = this->GetCurrentBinaryDirectory();
+ std::string cleanfile = currentBinaryDir;
+ cleanfile += "/CMakeFiles/cmake_directory_clean.cmake";
+ // Write clean script
+ {
+ std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile);
+ cmsys::ofstream fout(cleanfilePath.c_str());
+ if (!fout) {
+ cmSystemTools::Error("Could not create " + cleanfilePath);
+ return;
+ }
+ fout << "file(REMOVE_RECURSE\n";
+ for (std::string const& cfl : cleanFiles) {
+ std::string fc = rootLG->MaybeConvertToRelativePath(
+ binaryDir, cmSystemTools::CollapseFullPath(cfl, currentBinaryDir));
+ fout << " " << cmOutputConverter::EscapeForCMake(fc) << "\n";
+ }
+ fout << ")\n";
+ }
+ // Create command
+ {
+ std::string remove = "$(CMAKE_COMMAND) -P ";
+ remove += this->ConvertToOutputFormat(
+ rootLG->MaybeConvertToRelativePath(binaryDir, cleanfile),
+ cmOutputConverter::SHELL);
+ commands.push_back(std::move(remove));
+ }
+}
+
void cmLocalUnixMakefileGenerator3::AppendEcho(
std::vector<std::string>& commands, std::string const& text, EchoColor color,
EchoProgress const* progress)
@@ -1263,21 +1316,20 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
// Check if any multiple output pairs have a missing file.
this->CheckMultipleOutputs(verbose);
- std::string dir = cmSystemTools::GetFilenamePath(tgtInfo);
- std::string internalDependFile = dir + "/depend.internal";
- std::string dependFile = dir + "/depend.make";
+ std::string const targetDir = cmSystemTools::GetFilenamePath(tgtInfo);
+ std::string const internalDependFile = targetDir + "/depend.internal";
+ std::string const dependFile = targetDir + "/depend.make";
// If the target DependInfo.cmake file has changed since the last
// time dependencies were scanned then force rescanning. This may
// happen when a new source file is added and CMake regenerates the
// project but no other sources were touched.
bool needRescanDependInfo = false;
- cmFileTimeComparison* ftc =
- this->GlobalGenerator->GetCMakeInstance()->GetFileComparison();
+ cmFileTimeCache* ftc =
+ this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache();
{
int result;
- if (!ftc->FileTimeCompare(internalDependFile, tgtInfo, &result) ||
- result < 0) {
+ if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) {
if (verbose) {
std::ostringstream msg;
msg << "Dependee \"" << tgtInfo << "\" is newer than depender \""
@@ -1291,12 +1343,12 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
// If the directory information is newer than depend.internal, include dirs
// may have changed. In this case discard all old dependencies.
bool needRescanDirInfo = false;
- std::string dirInfoFile = this->GetCurrentBinaryDirectory();
- dirInfoFile += "/CMakeFiles";
- dirInfoFile += "/CMakeDirectoryInformation.cmake";
{
+ std::string dirInfoFile = this->GetCurrentBinaryDirectory();
+ dirInfoFile += "/CMakeFiles";
+ dirInfoFile += "/CMakeDirectoryInformation.cmake";
int result;
- if (!ftc->FileTimeCompare(internalDependFile, dirInfoFile, &result) ||
+ if (!ftc->Compare(internalDependFile, dirInfoFile, &result) ||
result < 0) {
if (verbose) {
std::ostringstream msg;
@@ -1312,12 +1364,12 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
// The build.make file may have explicit dependencies for the object
// files but these will not affect the scanning process so they need
// not be considered.
- std::map<std::string, cmDepends::DependencyVector> validDependencies;
+ cmDepends::DependencyMap validDependencies;
bool needRescanDependencies = false;
if (!needRescanDirInfo) {
cmDependsC checker;
checker.SetVerbose(verbose);
- checker.SetFileComparison(ftc);
+ checker.SetFileTimeCache(ftc);
// cmDependsC::Check() fills the vector validDependencies() with the
// dependencies for those files where they are still valid, i.e. neither
// the files themselves nor any files they depend on have changed.
@@ -1334,7 +1386,7 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) {
// The dependencies must be regenerated.
- std::string targetName = cmSystemTools::GetFilenameName(dir);
+ std::string targetName = cmSystemTools::GetFilenameName(targetDir);
targetName = targetName.substr(0, targetName.length() - 4);
std::string message = "Scanning dependencies of target ";
message += targetName;
@@ -1342,7 +1394,8 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
cmsysTerminal_Color_ForegroundBold,
message.c_str(), true, color);
- return this->ScanDependencies(dir, validDependencies);
+ return this->ScanDependencies(targetDir, dependFile, internalDependFile,
+ validDependencies);
}
// The dependencies are already up-to-date.
@@ -1350,17 +1403,20 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
}
bool cmLocalUnixMakefileGenerator3::ScanDependencies(
- const std::string& targetDir,
- std::map<std::string, cmDepends::DependencyVector>& validDeps)
+ std::string const& targetDir, std::string const& dependFile,
+ std::string const& internalDependFile, cmDepends::DependencyMap& validDeps)
{
// Read the directory information file.
cmMakefile* mf = this->Makefile;
bool haveDirectoryInfo = false;
- std::string dirInfoFile = this->GetCurrentBinaryDirectory();
- dirInfoFile += "/CMakeFiles";
- dirInfoFile += "/CMakeDirectoryInformation.cmake";
- if (mf->ReadListFile(dirInfoFile) && !cmSystemTools::GetErrorOccuredFlag()) {
- haveDirectoryInfo = true;
+ {
+ std::string dirInfoFile = this->GetCurrentBinaryDirectory();
+ dirInfoFile += "/CMakeFiles";
+ dirInfoFile += "/CMakeDirectoryInformation.cmake";
+ if (mf->ReadListFile(dirInfoFile) &&
+ !cmSystemTools::GetErrorOccuredFlag()) {
+ haveDirectoryInfo = true;
+ }
}
// Lookup useful directory information.
@@ -1389,10 +1445,8 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies(
// Open the make depends file. This should be copy-if-different
// because the make tool may try to reload it needlessly otherwise.
- std::string ruleFileNameFull = targetDir;
- ruleFileNameFull += "/depend.make";
cmGeneratedFileStream ruleFileStream(
- ruleFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding());
+ dependFile, false, this->GlobalGenerator->GetMakefileEncoding());
ruleFileStream.SetCopyIfDifferent(true);
if (!ruleFileStream) {
return false;
@@ -1401,11 +1455,8 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies(
// Open the cmake dependency tracking file. This should not be
// copy-if-different because dependencies are re-scanned when it is
// older than the DependInfo.cmake.
- std::string internalRuleFileNameFull = targetDir;
- internalRuleFileNameFull += "/depend.internal";
cmGeneratedFileStream internalRuleFileStream(
- internalRuleFileNameFull, false,
- this->GlobalGenerator->GetMakefileEncoding());
+ internalDependFile, false, this->GlobalGenerator->GetMakefileEncoding());
if (!internalRuleFileStream) {
return false;
}
@@ -1414,39 +1465,35 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies(
this->WriteDisclaimer(internalRuleFileStream);
// for each language we need to scan, scan it
- std::string const& langStr =
- mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES");
std::vector<std::string> langs;
- cmSystemTools::ExpandListArgument(langStr, langs);
+ cmSystemTools::ExpandListArgument(
+ mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES"), langs);
for (std::string const& lang : langs) {
// construct the checker
// Create the scanner for this language
- cmDepends* scanner = nullptr;
+ std::unique_ptr<cmDepends> scanner;
if (lang == "C" || lang == "CXX" || lang == "RC" || lang == "ASM" ||
lang == "CUDA") {
// TODO: Handle RC (resource files) dependencies correctly.
- scanner = new cmDependsC(this, targetDir, lang, &validDeps);
+ scanner = cm::make_unique<cmDependsC>(this, targetDir, lang, &validDeps);
}
#ifdef CMAKE_BUILD_WITH_CMAKE
else if (lang == "Fortran") {
ruleFileStream << "# Note that incremental build could trigger "
<< "a call to cmake_copy_f90_mod on each re-build\n";
- scanner = new cmDependsFortran(this);
+ scanner = cm::make_unique<cmDependsFortran>(this);
} else if (lang == "Java") {
- scanner = new cmDependsJava();
+ scanner = cm::make_unique<cmDependsJava>();
}
#endif
if (scanner) {
scanner->SetLocalGenerator(this);
- scanner->SetFileComparison(
- this->GlobalGenerator->GetCMakeInstance()->GetFileComparison());
+ scanner->SetFileTimeCache(
+ this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache());
scanner->SetLanguage(lang);
scanner->SetTargetDirectory(targetDir);
scanner->Write(ruleFileStream, internalRuleFileStream);
-
- // free the scanner for this language
- delete scanner;
}
}
diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h
index ced2dbd46..c8e4b0e97 100644
--- a/Source/cmLocalUnixMakefileGenerator3.h
+++ b/Source/cmLocalUnixMakefileGenerator3.h
@@ -143,8 +143,7 @@ public:
// File pairs for implicit dependency scanning. The key of the map
// is the depender and the value is the explicit dependee.
- struct ImplicitDependFileMap
- : public std::map<std::string, cmDepends::DependencyVector>
+ struct ImplicitDependFileMap : public cmDepends::DependencyMap
{
};
struct ImplicitDependLanguageMap
@@ -225,14 +224,16 @@ protected:
bool echo_comment = false,
std::ostream* content = nullptr);
void AppendCleanCommand(std::vector<std::string>& commands,
- const std::vector<std::string>& files,
+ const std::set<std::string>& files,
cmGeneratorTarget* target,
const char* filename = nullptr);
+ void AppendDirectoryCleanCommand(std::vector<std::string>& commands);
// Helper methods for dependency updates.
- bool ScanDependencies(
- const std::string& targetDir,
- std::map<std::string, cmDepends::DependencyVector>& validDeps);
+ bool ScanDependencies(std::string const& targetDir,
+ std::string const& dependFile,
+ std::string const& internalDependFile,
+ cmDepends::DependencyMap& validDeps);
void CheckMultipleOutputs(bool verbose);
private:
diff --git a/Source/cmLocalVisualStudio10Generator.h b/Source/cmLocalVisualStudio10Generator.h
index a4150b94d..5c6400e9f 100644
--- a/Source/cmLocalVisualStudio10Generator.h
+++ b/Source/cmLocalVisualStudio10Generator.h
@@ -21,7 +21,7 @@ class cmMakefile;
class cmLocalVisualStudio10Generator : public cmLocalVisualStudio7Generator
{
public:
- ///! Set cache only and recurse to false by default.
+ //! Set cache only and recurse to false by default.
cmLocalVisualStudio10Generator(cmGlobalGenerator* gg, cmMakefile* mf);
virtual ~cmLocalVisualStudio10Generator();
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 7019552c3..7ba347177 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmLocalVisualStudio7Generator.h"
+#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalVisualStudio7Generator.h"
@@ -118,8 +119,8 @@ void cmLocalVisualStudio7Generator::WriteProjectFiles()
// If not an in source build, then create the output directory
if (this->GetCurrentBinaryDirectory() != this->GetSourceDirectory()) {
if (!cmSystemTools::MakeDirectory(this->GetCurrentBinaryDirectory())) {
- cmSystemTools::Error("Error creating directory ",
- this->GetCurrentBinaryDirectory().c_str());
+ cmSystemTools::Error("Error creating directory " +
+ this->GetCurrentBinaryDirectory());
}
}
@@ -283,7 +284,7 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule()
file->GetFullPath();
return file;
} else {
- cmSystemTools::Error("Error adding rule for ", makefileIn.c_str());
+ cmSystemTools::Error("Error adding rule for " + makefileIn);
return nullptr;
}
}
@@ -293,9 +294,8 @@ void cmLocalVisualStudio7Generator::WriteConfigurations(
const std::string& libName, cmGeneratorTarget* target)
{
fout << "\t<Configurations>\n";
- for (std::vector<std::string>::const_iterator i = configs.begin();
- i != configs.end(); ++i) {
- this->WriteConfiguration(fout, i->c_str(), libName, target);
+ for (std::string const& config : configs) {
+ this->WriteConfiguration(fout, config.c_str(), libName, target);
}
fout << "\t</Configurations>\n";
}
@@ -569,9 +569,8 @@ public:
void Finish() { this->Stream << (this->First ? "" : "\"") << "/>\n"; }
void Write(std::vector<cmCustomCommand> const& ccs)
{
- for (std::vector<cmCustomCommand>::const_iterator ci = ccs.begin();
- ci != ccs.end(); ++ci) {
- this->Write(*ci);
+ for (cmCustomCommand const& command : ccs) {
+ this->Write(command);
}
}
void Write(cmCustomCommand const& cc)
@@ -656,21 +655,14 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
: target->GetLinkerLanguage(configName));
if (linkLanguage.empty()) {
cmSystemTools::Error(
- "CMake can not determine linker language for target: ",
- target->GetName().c_str());
+ "CMake can not determine linker language for target: " +
+ target->GetName());
return;
}
langForClCompile = linkLanguage;
if (langForClCompile == "C" || langForClCompile == "CXX" ||
langForClCompile == "Fortran") {
- std::string baseFlagVar = "CMAKE_";
- baseFlagVar += langForClCompile;
- baseFlagVar += "_FLAGS";
- flags = this->Makefile->GetRequiredDefinition(baseFlagVar);
- std::string flagVar =
- baseFlagVar + std::string("_") + cmSystemTools::UpperCase(configName);
- flags += " ";
- flags += this->Makefile->GetRequiredDefinition(flagVar);
+ this->AddLanguageFlags(flags, target, langForClCompile, configName);
}
// set the correct language
if (linkLanguage == "C") {
@@ -897,10 +889,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
target->GetManifests(manifest_srcs, configName);
if (!manifest_srcs.empty()) {
fout << "\n\t\t\t\tAdditionalManifestFiles=\"";
- for (std::vector<cmSourceFile const*>::const_iterator mi =
- manifest_srcs.begin();
- mi != manifest_srcs.end(); ++mi) {
- std::string m = (*mi)->GetFullPath();
+ for (cmSourceFile const* manifest : manifest_srcs) {
+ std::string m = manifest->GetFullPath();
fout << this->ConvertToXMLOutputPath(m.c_str()) << ";";
}
fout << "\"";
@@ -931,7 +921,7 @@ std::string cmLocalVisualStudio7Generator::GetBuildTypeLinkerFlags(
std::string extraLinkOptionsBuildTypeDef =
rootLinkerFlags + "_" + configTypeUpper;
- std::string extraLinkOptionsBuildType =
+ const std::string& extraLinkOptionsBuildType =
this->Makefile->GetRequiredDefinition(extraLinkOptionsBuildTypeDef);
return extraLinkOptionsBuildType;
@@ -947,21 +937,18 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
std::string extraLinkOptions;
if (target->GetType() == cmStateEnums::EXECUTABLE) {
extraLinkOptions =
- this->Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS") +
- std::string(" ") +
+ this->Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS") + " " +
GetBuildTypeLinkerFlags("CMAKE_EXE_LINKER_FLAGS", configName);
}
if (target->GetType() == cmStateEnums::SHARED_LIBRARY) {
extraLinkOptions =
this->Makefile->GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS") +
- std::string(" ") +
- GetBuildTypeLinkerFlags("CMAKE_SHARED_LINKER_FLAGS", configName);
+ " " + GetBuildTypeLinkerFlags("CMAKE_SHARED_LINKER_FLAGS", configName);
}
if (target->GetType() == cmStateEnums::MODULE_LIBRARY) {
extraLinkOptions =
this->Makefile->GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS") +
- std::string(" ") +
- GetBuildTypeLinkerFlags("CMAKE_MODULE_LINKER_FLAGS", configName);
+ " " + GetBuildTypeLinkerFlags("CMAKE_MODULE_LINKER_FLAGS", configName);
}
const char* targetLinkFlags = target->GetProperty("LINK_FLAGS");
@@ -1050,13 +1037,8 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
}
case cmStateEnums::SHARED_LIBRARY:
case cmStateEnums::MODULE_LIBRARY: {
- std::string targetName;
- std::string targetNameSO;
- std::string targetNameFull;
- std::string targetNameImport;
- std::string targetNamePDB;
- target->GetLibraryNames(targetName, targetNameSO, targetNameFull,
- targetNameImport, targetNamePDB, configName);
+ cmGeneratorTarget::Names targetNames =
+ target->GetLibraryNames(configName);
// Compute the link library and directory information.
cmComputeLinkInformation* pcli = target->GetLinkInformation(configName);
@@ -1092,7 +1074,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
fout << "\"\n";
temp = target->GetDirectory(configName);
temp += "/";
- temp += targetNameFull;
+ temp += targetNames.Output;
fout << "\t\t\t\tOutputFile=\""
<< this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
this->WriteTargetVersionAttribute(fout, target);
@@ -1102,7 +1084,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
fout << "\"\n";
temp = target->GetPDBDirectory(configName);
temp += "/";
- temp += targetNamePDB;
+ temp += targetNames.PDB;
fout << "\t\t\t\tProgramDatabaseFile=\""
<< this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
if (targetOptions.IsDebug()) {
@@ -1125,7 +1107,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
temp =
target->GetDirectory(configName, cmStateEnums::ImportLibraryArtifact);
temp += "/";
- temp += targetNameImport;
+ temp += targetNames.ImportLibrary;
fout << "\t\t\t\tImportLibrary=\""
<< this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"";
if (this->FortranProject) {
@@ -1134,12 +1116,8 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
fout << "/>\n";
} break;
case cmStateEnums::EXECUTABLE: {
- std::string targetName;
- std::string targetNameFull;
- std::string targetNameImport;
- std::string targetNamePDB;
- target->GetExecutableNames(targetName, targetNameFull, targetNameImport,
- targetNamePDB, configName);
+ cmGeneratorTarget::Names targetNames =
+ target->GetExecutableNames(configName);
// Compute the link library and directory information.
cmComputeLinkInformation* pcli = target->GetLinkInformation(configName);
@@ -1177,7 +1155,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
fout << "\"\n";
temp = target->GetDirectory(configName);
temp += "/";
- temp += targetNameFull;
+ temp += targetNames.Output;
fout << "\t\t\t\tOutputFile=\""
<< this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
this->WriteTargetVersionAttribute(fout, target);
@@ -1187,8 +1165,8 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
fout << "\"\n";
std::string path = this->ConvertToXMLOutputPathSingle(
target->GetPDBDirectory(configName).c_str());
- fout << "\t\t\t\tProgramDatabaseFile=\"" << path << "/" << targetNamePDB
- << "\"\n";
+ fout << "\t\t\t\tProgramDatabaseFile=\"" << path << "/"
+ << targetNames.PDB << "\"\n";
if (targetOptions.IsDebug()) {
fout << "\t\t\t\tGenerateDebugInformation=\"true\"\n";
}
@@ -1223,7 +1201,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
temp =
target->GetDirectory(configName, cmStateEnums::ImportLibraryArtifact);
temp += "/";
- temp += targetNameImport;
+ temp += targetNames.ImportLibrary;
fout << "\t\t\t\tImportLibrary=\""
<< this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"/>\n";
break;
@@ -1303,14 +1281,14 @@ void cmLocalVisualStudio7GeneratorInternals::OutputLibraries(
{
cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
std::string currentBinDir = lg->GetCurrentBinaryDirectory();
- for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) {
- if (l->IsPath) {
+ for (auto const& lib : libs) {
+ if (lib.IsPath) {
std::string rel =
- lg->MaybeConvertToRelativePath(currentBinDir, l->Value.c_str());
+ lg->MaybeConvertToRelativePath(currentBinDir, lib.Value.c_str());
fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " ";
- } else if (!l->Target ||
- l->Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
- fout << l->Value << " ";
+ } else if (!lib.Target ||
+ lib.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+ fout << lib.Value << " ";
}
}
}
@@ -1328,10 +1306,9 @@ void cmLocalVisualStudio7GeneratorInternals::OutputObjects(
gt->GetExternalObjects(objs, configName);
const char* sep = isep ? isep : "";
- for (std::vector<cmSourceFile const*>::const_iterator i = objs.begin();
- i != objs.end(); ++i) {
- if (!(*i)->GetObjectLibrary().empty()) {
- std::string const& objFile = (*i)->GetFullPath();
+ for (cmSourceFile const* obj : objs) {
+ if (!obj->GetObjectLibrary().empty()) {
+ std::string const& objFile = obj->GetFullPath();
std::string rel = lg->MaybeConvertToRelativePath(currentBinDir, objFile);
fout << sep << lg->ConvertToXMLOutputPath(rel.c_str());
sep = " ";
@@ -1344,10 +1321,8 @@ void cmLocalVisualStudio7Generator::OutputLibraryDirectories(
{
const char* comma = "";
std::string currentBinDir = this->GetCurrentBinaryDirectory();
- for (std::vector<std::string>::const_iterator d = dirs.begin();
- d != dirs.end(); ++d) {
+ for (std::string dir : dirs) {
// Remove any trailing slash and skip empty paths.
- std::string dir = *d;
if (dir.back() == '/') {
dir = dir.substr(0, dir.size() - 1);
}
@@ -1483,9 +1458,8 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
// Compute per-source, per-config information.
size_t ci = 0;
- for (std::vector<std::string>::const_iterator i = configs.begin();
- i != configs.end(); ++i, ++ci) {
- std::string configUpper = cmSystemTools::UpperCase(*i);
+ for (std::string const& config : configs) {
+ std::string configUpper = cmSystemTools::UpperCase(config);
cmLVS7GFileConfig fc;
std::string lang =
@@ -1498,7 +1472,7 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
lang = sourceLang;
}
- cmGeneratorExpressionInterpreter genexInterpreter(lg, *i, gt, lang);
+ cmGeneratorExpressionInterpreter genexInterpreter(lg, config, gt, lang);
bool needfc = false;
if (!objectName.empty()) {
@@ -1564,7 +1538,7 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
}
}
- const std::string& linkLanguage = gt->GetLinkerLanguage(i->c_str());
+ const std::string& linkLanguage = gt->GetLinkerLanguage(config.c_str());
// If HEADER_FILE_ONLY is set, we must suppress this generation in
// the project file
fc.ExcludedFromBuild = sf.GetPropertyAsBool("HEADER_FILE_ONLY") ||
@@ -1589,8 +1563,9 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
}
if (needfc) {
- this->FileConfigMap[*i] = fc;
+ this->FileConfigMap[config] = fc;
}
+ ++ci;
}
}
@@ -1654,16 +1629,14 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
}
// Loop through each source in the source group.
- for (std::vector<const cmSourceFile*>::const_iterator sf =
- sourceFiles.begin();
- sf != sourceFiles.end(); ++sf) {
- std::string source = (*sf)->GetFullPath();
+ for (const cmSourceFile* sf : sourceFiles) {
+ std::string source = sf->GetFullPath();
if (source != libName || target->GetType() == cmStateEnums::UTILITY ||
target->GetType() == cmStateEnums::GLOBAL_TARGET) {
// Look up the source kind and configs.
std::map<cmSourceFile const*, size_t>::const_iterator map_it =
- sources.Index.find(*sf);
+ sources.Index.find(sf);
// The map entry must exist because we populated it earlier.
assert(map_it != sources.Index.end());
cmGeneratorTarget::AllConfigSource const& acs =
@@ -1676,7 +1649,7 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
// Tell MS-Dev what the source is. If the compiler knows how to
// build it, then it will.
fout << "\t\t\t\tRelativePath=\"" << d << "\">\n";
- if (cmCustomCommand const* command = (*sf)->GetCustomCommand()) {
+ if (cmCustomCommand const* command = sf->GetCustomCommand()) {
this->WriteCustomRule(fout, configs, source.c_str(), *command, fcinfo);
} else if (!fcinfo.FileConfigMap.empty()) {
const char* aCompilerTool = "VCCLCompilerTool";
@@ -1684,8 +1657,8 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
if (this->FortranProject) {
aCompilerTool = "VFFortranCompilerTool";
}
- std::string const& lang = (*sf)->GetLanguage();
- std::string ext = (*sf)->GetExtension();
+ std::string const& lang = sf->GetLanguage();
+ std::string ext = sf->GetExtension();
ext = cmSystemTools::LowerCase(ext);
if (ext == "idl") {
aCompilerTool = "VCMIDLTool";
@@ -1713,12 +1686,10 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
if (acs.Kind == cmGeneratorTarget::SourceKindExternalObject) {
aCompilerTool = "VCCustomBuildTool";
}
- for (std::map<std::string, cmLVS7GFileConfig>::const_iterator fci =
- fcinfo.FileConfigMap.begin();
- fci != fcinfo.FileConfigMap.end(); ++fci) {
- cmLVS7GFileConfig const& fc = fci->second;
+ for (auto const& fci : fcinfo.FileConfigMap) {
+ cmLVS7GFileConfig const& fc = fci.second;
fout << "\t\t\t\t<FileConfiguration\n"
- << "\t\t\t\t\tName=\"" << fci->first << "|"
+ << "\t\t\t\t\tName=\"" << fci.first << "|"
<< gg->GetPlatformName() << "\"";
if (fc.ExcludedFromBuild) {
fout << " ExcludedFromBuild=\"true\"";
@@ -1741,7 +1712,7 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
fileOptions.AddDefines(fc.CompileDefsConfig);
// validate source level include directories
std::vector<std::string> includes;
- this->AppendIncludeDirectories(includes, fc.IncludeDirs, **sf);
+ this->AppendIncludeDirectories(includes, fc.IncludeDirs, *sf);
fileOptions.AddIncludes(includes);
fileOptions.OutputFlagMap(fout, 5);
fileOptions.OutputAdditionalIncludeDirectories(
@@ -1794,12 +1765,11 @@ void cmLocalVisualStudio7Generator::WriteCustomRule(
if (this->FortranProject) {
customTool = "VFCustomBuildTool";
}
- for (std::vector<std::string>::const_iterator i = configs.begin();
- i != configs.end(); ++i) {
- cmCustomCommandGenerator ccg(command, *i, this);
- cmLVS7GFileConfig const& fc = fcinfo.FileConfigMap[*i];
+ for (std::string const& config : configs) {
+ cmCustomCommandGenerator ccg(command, config, this);
+ cmLVS7GFileConfig const& fc = fcinfo.FileConfigMap[config];
fout << "\t\t\t\t<FileConfiguration\n";
- fout << "\t\t\t\t\tName=\"" << *i << "|" << gg->GetPlatformName()
+ fout << "\t\t\t\t\tName=\"" << config << "|" << gg->GetPlatformName()
<< "\">\n";
if (!fc.CompileFlags.empty()) {
fout << "\t\t\t\t\t<Tool\n"
@@ -1811,7 +1781,7 @@ void cmLocalVisualStudio7Generator::WriteCustomRule(
std::string comment = this->ConstructComment(ccg);
std::string script = this->ConstructScript(ccg);
if (this->FortranProject) {
- cmSystemTools::ReplaceString(script, "$(Configuration)", i->c_str());
+ cmSystemTools::ReplaceString(script, "$(Configuration)", config.c_str());
}
/* clang-format off */
fout << "\t\t\t\t\t<Tool\n"
@@ -1832,12 +1802,10 @@ void cmLocalVisualStudio7Generator::WriteCustomRule(
fout << this->ConvertToXMLOutputPath(source);
} else {
// Write out the dependencies for the rule.
- for (std::vector<std::string>::const_iterator d =
- ccg.GetDepends().begin();
- d != ccg.GetDepends().end(); ++d) {
+ for (std::string const& d : ccg.GetDepends()) {
// Get the real name of the dependency in case it is a CMake target.
std::string dep;
- if (this->GetRealDependency(d->c_str(), i->c_str(), dep)) {
+ if (this->GetRealDependency(d.c_str(), config.c_str(), dep)) {
fout << this->ConvertToXMLOutputPath(dep.c_str()) << ";";
}
}
@@ -1849,10 +1817,8 @@ void cmLocalVisualStudio7Generator::WriteCustomRule(
} else {
// Write a rule for the output generated by this command.
const char* sep = "";
- for (std::vector<std::string>::const_iterator o =
- ccg.GetOutputs().begin();
- o != ccg.GetOutputs().end(); ++o) {
- fout << sep << this->ConvertToXMLOutputPathSingle(o->c_str());
+ for (std::string const& output : ccg.GetOutputs()) {
+ fout << sep << this->ConvertToXMLOutputPathSingle(output.c_str());
sep = ";";
}
}
@@ -2063,16 +2029,14 @@ void cmLocalVisualStudio7Generator::WriteVCProjFooter(
{
fout << "\t<Globals>\n";
- std::vector<std::string> const& props = target->GetPropertyKeys();
- for (std::vector<std::string>::const_iterator i = props.begin();
- i != props.end(); ++i) {
- if (i->find("VS_GLOBAL_") == 0) {
- std::string name = i->substr(10);
+ for (std::string const& key : target->GetPropertyKeys()) {
+ if (key.find("VS_GLOBAL_") == 0) {
+ std::string name = key.substr(10);
if (!name.empty()) {
/* clang-format off */
fout << "\t\t<Global\n"
<< "\t\t\tName=\"" << name << "\"\n"
- << "\t\t\tValue=\"" << target->GetProperty(*i) << "\"\n"
+ << "\t\t\tValue=\"" << target->GetProperty(key) << "\"\n"
<< "\t\t/>\n";
/* clang-format on */
}
diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h
index b093e6fc9..ce8eceb7e 100644
--- a/Source/cmLocalVisualStudio7Generator.h
+++ b/Source/cmLocalVisualStudio7Generator.h
@@ -43,7 +43,7 @@ public:
class cmLocalVisualStudio7Generator : public cmLocalVisualStudioGenerator
{
public:
- ///! Set cache only and recurse to false by default.
+ //! Set cache only and recurse to false by default.
cmLocalVisualStudio7Generator(cmGlobalGenerator* gg, cmMakefile* mf);
virtual ~cmLocalVisualStudio7Generator();
diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx
index 660729c3a..f3f2042ec 100644
--- a/Source/cmLocalVisualStudioGenerator.cxx
+++ b/Source/cmLocalVisualStudioGenerator.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmLocalVisualStudioGenerator.h"
+#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
diff --git a/Source/cmLocalXCodeGenerator.h b/Source/cmLocalXCodeGenerator.h
index 5c22dcf68..42de20b47 100644
--- a/Source/cmLocalXCodeGenerator.h
+++ b/Source/cmLocalXCodeGenerator.h
@@ -24,7 +24,7 @@ class cmSourceFile;
class cmLocalXCodeGenerator : public cmLocalGenerator
{
public:
- ///! Set cache only and recurse to false by default.
+ //! Set cache only and recurse to false by default.
cmLocalXCodeGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
~cmLocalXCodeGenerator() override;
diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx
index 7279d5fcf..e9c6aea73 100644
--- a/Source/cmMacroCommand.cxx
+++ b/Source/cmMacroCommand.cxx
@@ -10,6 +10,7 @@
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmPolicies.h"
+#include "cmRange.h"
#include "cmState.h"
#include "cmSystemTools.h"
@@ -211,7 +212,7 @@ bool cmMacroCommand::InitialPass(std::vector<std::string> const& args,
// create a function blocker
cmMacroFunctionBlocker* f = new cmMacroFunctionBlocker();
- f->Args.insert(f->Args.end(), args.begin(), args.end());
+ cmAppend(f->Args, args);
this->Makefile->AddFunctionBlocker(f);
return true;
}
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 27351226f..e0f69cb4b 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -31,6 +31,7 @@
#include "cmInstallSubdirectoryGenerator.h"
#include "cmListFileCache.h"
#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmSourceFileLocation.h"
#include "cmState.h"
@@ -292,13 +293,14 @@ void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const
std::string const& only_filename = cmSystemTools::GetFilenameName(full_path);
bool trace = trace_only_this_files.empty();
if (!trace) {
- for (std::vector<std::string>::const_iterator i =
- trace_only_this_files.begin();
- !trace && i != trace_only_this_files.end(); ++i) {
- std::string::size_type const pos = full_path.rfind(*i);
+ for (std::string const& file : trace_only_this_files) {
+ std::string::size_type const pos = full_path.rfind(file);
trace = (pos != std::string::npos) &&
- ((pos + i->size()) == full_path.size()) &&
- (only_filename == cmSystemTools::GetFilenameName(*i));
+ ((pos + file.size()) == full_path.size()) &&
+ (only_filename == cmSystemTools::GetFilenameName(file));
+ if (trace) {
+ break;
+ }
}
// Do nothing if current file wasn't requested for trace...
if (!trace) {
@@ -347,6 +349,9 @@ public:
this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
}
+ cmMakefileCall(const cmMakefileCall&) = delete;
+ cmMakefileCall& operator=(const cmMakefileCall&) = delete;
+
private:
cmMakefile* Makefile;
};
@@ -438,6 +443,9 @@ public:
~IncludeScope();
void Quiet() { this->ReportError = false; }
+ IncludeScope(const IncludeScope&) = delete;
+ IncludeScope& operator=(const IncludeScope&) = delete;
+
private:
cmMakefile* Makefile;
bool NoPolicyScope;
@@ -605,6 +613,9 @@ public:
void Quiet() { this->ReportError = false; }
+ ListFileScope(const ListFileScope&) = delete;
+ ListFileScope& operator=(const ListFileScope&) = delete;
+
private:
cmMakefile* Makefile;
bool ReportError;
@@ -803,11 +814,11 @@ void cmMakefile::AddCustomCommandToTarget(
const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type,
const char* comment, const char* workingDir, bool escapeOldStyle,
- bool uses_terminal, const std::string& depfile, bool command_expand_lists,
- ObjectLibraryCommands objLibraryCommands)
+ bool uses_terminal, const std::string& depfile, const std::string& job_pool,
+ bool command_expand_lists, ObjectLibraryCommands objLibraryCommands)
{
// Find the target to which to add the custom command.
- cmTargets::iterator ti = this->Targets.find(target);
+ cmTargetMap::iterator ti = this->Targets.find(target);
if (ti == this->Targets.end()) {
MessageType messageType = MessageType::AUTHOR_WARNING;
@@ -879,6 +890,7 @@ void cmMakefile::AddCustomCommandToTarget(
cc.SetUsesTerminal(uses_terminal);
cc.SetCommandExpandLists(command_expand_lists);
cc.SetDepfile(depfile);
+ cc.SetJobPool(job_pool);
switch (type) {
case cmTarget::PRE_BUILD:
t.AddPreBuildCommand(cc);
@@ -898,7 +910,8 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
const std::vector<std::string>& depends, const std::string& main_dependency,
const cmCustomCommandLines& commandLines, const char* comment,
const char* workingDir, bool replace, bool escapeOldStyle,
- bool uses_terminal, bool command_expand_lists, const std::string& depfile)
+ bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+ const std::string& job_pool)
{
// Make sure there is at least one output.
if (outputs.empty()) {
@@ -949,9 +962,8 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
if (file && file->GetCustomCommand() && !replace) {
// The rule file already exists.
if (commandLines != file->GetCustomCommand()->GetCommandLines()) {
- cmSystemTools::Error("Attempt to add a custom rule to output \"",
- outName.c_str(),
- "\" which already has a custom rule.");
+ cmSystemTools::Error("Attempt to add a custom rule to output \"" +
+ outName + "\" which already has a custom rule.");
}
return file;
}
@@ -993,6 +1005,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
cc->SetUsesTerminal(uses_terminal);
cc->SetCommandExpandLists(command_expand_lists);
cc->SetDepfile(depfile);
+ cc->SetJobPool(job_pool);
file->SetCustomCommand(cc);
this->UpdateOutputToSourceMap(outputs, file);
}
@@ -1030,7 +1043,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
const std::string& main_dependency, const cmCustomCommandLines& commandLines,
const char* comment, const char* workingDir, bool replace,
bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
- const std::string& depfile)
+ const std::string& depfile, const std::string& job_pool)
{
std::vector<std::string> outputs;
outputs.push_back(output);
@@ -1038,7 +1051,7 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
return this->AddCustomCommandToOutput(
outputs, no_byproducts, depends, main_dependency, commandLines, comment,
workingDir, replace, escapeOldStyle, uses_terminal, command_expand_lists,
- depfile);
+ depfile, job_pool);
}
void cmMakefile::AddCustomCommandOldStyle(
@@ -1086,13 +1099,13 @@ void cmMakefile::AddCustomCommandOldStyle(
// then add the source to the target to make sure the rule is
// included.
if (sf && !sf->GetPropertyAsBool("__CMAKE_RULE")) {
- cmTargets::iterator ti = this->Targets.find(target);
+ cmTargetMap::iterator ti = this->Targets.find(target);
if (ti != this->Targets.end()) {
ti->second.AddSource(sf->GetFullPath());
} else {
cmSystemTools::Error("Attempt to add a custom rule to a target "
- "that does not exist yet for target ",
- target.c_str());
+ "that does not exist yet for target " +
+ target);
return;
}
}
@@ -1132,13 +1145,14 @@ cmTarget* cmMakefile::AddUtilityCommand(
const std::string& utilityName, TargetOrigin origin, bool excludeFromAll,
const char* workingDirectory, const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, bool escapeOldStyle,
- const char* comment, bool uses_terminal, bool command_expand_lists)
+ const char* comment, bool uses_terminal, bool command_expand_lists,
+ const std::string& job_pool)
{
std::vector<std::string> no_byproducts;
- return this->AddUtilityCommand(utilityName, origin, excludeFromAll,
- workingDirectory, no_byproducts, depends,
- commandLines, escapeOldStyle, comment,
- uses_terminal, command_expand_lists);
+ return this->AddUtilityCommand(
+ utilityName, origin, excludeFromAll, workingDirectory, no_byproducts,
+ depends, commandLines, escapeOldStyle, comment, uses_terminal,
+ command_expand_lists, job_pool);
}
cmTarget* cmMakefile::AddUtilityCommand(
@@ -1146,12 +1160,13 @@ cmTarget* cmMakefile::AddUtilityCommand(
const char* workingDirectory, const std::vector<std::string>& byproducts,
const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, bool escapeOldStyle,
- const char* comment, bool uses_terminal, bool command_expand_lists)
+ const char* comment, bool uses_terminal, bool command_expand_lists,
+ const std::string& job_pool)
{
// Create a target instance for this utility.
cmTarget* target = this->AddNewTarget(cmStateEnums::UTILITY, utilityName);
target->SetIsGeneratorProvided(origin == TargetOrigin::Generator);
- if (excludeFromAll) {
+ if (excludeFromAll || this->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
}
if (!comment) {
@@ -1172,15 +1187,14 @@ cmTarget* cmMakefile::AddUtilityCommand(
this->AddCustomCommandToOutput(
forced, byproducts, depends, no_main_dependency, commandLines, comment,
workingDirectory, no_replace, escapeOldStyle, uses_terminal,
- command_expand_lists);
+ command_expand_lists, /*depfile=*/"", job_pool);
cmSourceFile* sf = target->AddSourceCMP0049(force);
// The output is not actually created so mark it symbolic.
if (sf) {
sf->SetProperty("SYMBOLIC", "1");
} else {
- cmSystemTools::Error("Could not get source file entry for ",
- force.c_str());
+ cmSystemTools::Error("Could not get source file entry for " + force);
}
// Always create the byproduct sources and mark them generated.
@@ -1496,6 +1510,9 @@ public:
void Quiet() { this->ReportError = false; }
+ BuildsystemFileScope(const BuildsystemFileScope&) = delete;
+ BuildsystemFileScope& operator=(const BuildsystemFileScope&) = delete;
+
private:
cmMakefile* Makefile;
cmGlobalGenerator* GG;
@@ -1587,6 +1604,16 @@ void cmMakefile::Configure()
}
// if no project command is found, add one
if (!hasProject) {
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ "No project() command is present. The top-level CMakeLists.txt "
+ "file must contain a literal, direct call to the project() command. "
+ "Add a line of code such as\n"
+ " project(ProjectName)\n"
+ "near the top of the file, but after cmake_minimum_required().\n"
+ "CMake is pretending there is a \"project(Project)\" command on "
+ "the first line.",
+ this->Backtrace);
cmListFileFunction project;
project.Name.Lower = "project";
project.Arguments.emplace_back("Project", cmListFileArgument::Unquoted,
@@ -1689,7 +1716,7 @@ void cmMakefile::AddSubDirectory(const std::string& srcPath,
cmMakefile* subMf = new cmMakefile(this->GlobalGenerator, newSnapshot);
this->GetGlobalGenerator()->AddMakefile(subMf);
- if (excludeFromAll) {
+ if (excludeFromAll || this->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
subMf->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
}
@@ -1848,10 +1875,8 @@ void cmMakefile::CheckForUnusedVariables() const
if (!this->WarnUnused) {
return;
}
- const std::vector<std::string>& unused = this->StateSnapshot.UnusedKeys();
- std::vector<std::string>::const_iterator it = unused.begin();
- for (; it != unused.end(); ++it) {
- this->LogUnused("out of scope", *it);
+ for (const std::string& key : this->StateSnapshot.UnusedKeys()) {
+ this->LogUnused("out of scope", key);
}
}
@@ -1985,7 +2010,9 @@ cmTarget* cmMakefile::AddLibrary(const std::string& lname,
// over changes in CMakeLists.txt, making the information stale and
// hence useless.
target->ClearDependencyInformation(*this);
- if (excludeFromAll) {
+ if (excludeFromAll ||
+ (type != cmStateEnums::INTERFACE_LIBRARY &&
+ this->GetPropertyAsBool("EXCLUDE_FROM_ALL"))) {
target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
}
target->AddSources(srcs);
@@ -1998,7 +2025,7 @@ cmTarget* cmMakefile::AddExecutable(const std::string& exeName,
bool excludeFromAll)
{
cmTarget* target = this->AddNewTarget(cmStateEnums::EXECUTABLE, exeName);
- if (excludeFromAll) {
+ if (excludeFromAll || this->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
}
target->AddSources(srcs);
@@ -2009,10 +2036,9 @@ cmTarget* cmMakefile::AddExecutable(const std::string& exeName,
cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type,
const std::string& name)
{
- cmTargets::iterator it =
+ cmTargetMap::iterator it =
this->Targets
- .insert(cmTargets::value_type(
- name, cmTarget(name, type, cmTarget::VisibilityNormal, this)))
+ .emplace(name, cmTarget(name, type, cmTarget::VisibilityNormal, this))
.first;
this->GetGlobalGenerator()->IndexTarget(&it->second);
this->GetStateSnapshot().GetDirectory().AddNormalTargetName(name);
@@ -2193,7 +2219,7 @@ cmSourceGroup* cmMakefile::FindSourceGroup(
}
// Shouldn't get here, but just in case, return the default group.
- return &groups.front();
+ return groups.data();
}
#endif
@@ -2425,16 +2451,19 @@ bool cmMakefile::CanIWriteThisFile(std::string const& fileName) const
cmSystemTools::SameFile(fileName, this->GetHomeOutputDirectory());
}
-std::string cmMakefile::GetRequiredDefinition(const std::string& name) const
+const std::string& cmMakefile::GetRequiredDefinition(
+ const std::string& name) const
{
- const char* ret = this->GetDefinition(name);
- if (!ret) {
+ static std::string const empty;
+ const std::string* def = GetDef(name);
+ if (!def) {
cmSystemTools::Error("Error required internal CMake variable not "
- "set, cmake may not be built correctly.\n",
- "Missing variable is:\n", name.c_str());
- return std::string();
+ "set, cmake may not be built correctly.\n"
+ "Missing variable is:\n" +
+ name);
+ return empty;
}
- return std::string(ret);
+ return *def;
}
bool cmMakefile::IsDefinitionSet(const std::string& name) const
@@ -2505,8 +2534,7 @@ const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const
std::vector<std::string> cmMakefile::GetDefinitions() const
{
std::vector<std::string> res = this->StateSnapshot.ClosureKeys();
- std::vector<std::string> cacheKeys = this->GetState()->GetCacheEntryKeys();
- res.insert(res.end(), cacheKeys.begin(), cacheKeys.end());
+ cmAppend(res, this->GetState()->GetCacheEntryKeys());
std::sort(res.begin(), res.end());
return res;
}
@@ -3055,10 +3083,8 @@ bool cmMakefile::IsFunctionBlocked(const cmListFileFunction& lff,
// loop over all function blockers to see if any block this command
// evaluate in reverse, this is critical for balanced IF statements etc
- std::vector<cmFunctionBlocker*>::reverse_iterator pos;
- for (pos = this->FunctionBlockers.rbegin();
- pos != this->FunctionBlockers.rend(); ++pos) {
- if ((*pos)->IsFunctionBlocked(lff, *this, status)) {
+ for (cmFunctionBlocker* pos : cmReverseRange(this->FunctionBlockers)) {
+ if (pos->IsFunctionBlocked(lff, *this, status)) {
return true;
}
}
@@ -3546,7 +3572,7 @@ cmState* cmMakefile::GetState() const
return this->GetCMakeInstance()->GetState();
}
-void cmMakefile::DisplayStatus(const char* message, float s) const
+void cmMakefile::DisplayStatus(const std::string& message, float s) const
{
cmake* cm = this->GetCMakeInstance();
if (cm->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
@@ -3716,22 +3742,23 @@ void cmMakefile::ConfigureString(const std::string& input, std::string& output,
lineNumber, true, true);
}
-int cmMakefile::ConfigureFile(const char* infile, const char* outfile,
- bool copyonly, bool atOnly, bool escapeQuotes,
+int cmMakefile::ConfigureFile(const std::string& infile,
+ const std::string& outfile, bool copyonly,
+ bool atOnly, bool escapeQuotes,
cmNewLineStyle newLine)
{
int res = 1;
if (!this->CanIWriteThisFile(outfile)) {
- cmSystemTools::Error("Attempt to write file: ", outfile,
+ cmSystemTools::Error("Attempt to write file: " + outfile +
" into a source directory.");
return 0;
}
if (!cmSystemTools::FileExists(infile)) {
- cmSystemTools::Error("File ", infile, " does not exist.");
+ cmSystemTools::Error("File " + infile + " does not exist.");
return 0;
}
std::string soutfile = outfile;
- std::string sinfile = infile;
+ const std::string& sinfile = infile;
this->AddCMakeDependFile(sinfile);
cmSystemTools::ConvertToUnixSlashes(soutfile);
@@ -3765,15 +3792,15 @@ int cmMakefile::ConfigureFile(const char* infile, const char* outfile,
tempOutputFile += ".tmp";
cmsys::ofstream fout(tempOutputFile.c_str(), omode);
if (!fout) {
- cmSystemTools::Error("Could not open file for write in copy operation ",
- tempOutputFile.c_str());
+ cmSystemTools::Error("Could not open file for write in copy operation " +
+ tempOutputFile);
cmSystemTools::ReportLastSystemError("");
return 0;
}
cmsys::ifstream fin(sinfile.c_str());
if (!fin) {
- cmSystemTools::Error("Could not open file for read in copy operation ",
- sinfile.c_str());
+ cmSystemTools::Error("Could not open file for read in copy operation " +
+ sinfile);
return 0;
}
@@ -3860,7 +3887,7 @@ std::vector<std::string> cmMakefile::GetPropertyKeys() const
cmTarget* cmMakefile::FindLocalNonAliasTarget(const std::string& name) const
{
- cmTargets::iterator i = this->Targets.find(name);
+ cmTargetMap::iterator i = this->Targets.find(name);
if (i != this->Targets.end()) {
return &i->second;
}
@@ -4273,7 +4300,7 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id,
// Deprecate old policies, especially those that require a lot
// of code to maintain the old behavior.
- if (status == cmPolicies::OLD && id <= cmPolicies::CMP0065 &&
+ if (status == cmPolicies::OLD && id <= cmPolicies::CMP0066 &&
!(this->GetCMakeInstance()->GetIsInTryCompile() &&
(
// Policies set by cmCoreTryCompile::TryCompileCode.
@@ -4711,6 +4738,13 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target,
needCxx17, needCxx20);
const char* existingCxxStandard = target->GetProperty("CXX_STANDARD");
+ if (existingCxxStandard == nullptr) {
+ const char* defaultCxxStandard =
+ this->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT");
+ if (defaultCxxStandard && *defaultCxxStandard) {
+ existingCxxStandard = defaultCxxStandard;
+ }
+ }
const char* const* existingCxxLevel = nullptr;
if (existingCxxStandard) {
existingCxxLevel =
@@ -4813,6 +4847,13 @@ bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target,
this->CheckNeededCLanguage(feature, needC90, needC99, needC11);
const char* existingCStandard = target->GetProperty("C_STANDARD");
+ if (existingCStandard == nullptr) {
+ const char* defaultCStandard =
+ this->GetDefinition("CMAKE_C_STANDARD_DEFAULT");
+ if (defaultCStandard && *defaultCStandard) {
+ existingCStandard = defaultCStandard;
+ }
+ }
if (existingCStandard) {
if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS),
cmStrCmp(existingCStandard)) == cm::cend(C_STANDARDS)) {
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 70a5689e1..d22334751 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -150,7 +150,7 @@ public:
const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type,
const char* comment, const char* workingDir, bool escapeOldStyle = true,
bool uses_terminal = false, const std::string& depfile = "",
- bool command_expand_lists = false,
+ const std::string& job_pool = "", bool command_expand_lists = false,
ObjectLibraryCommands objLibraryCommands = RejectObjectLibraryCommands);
cmSourceFile* AddCustomCommandToOutput(
const std::vector<std::string>& outputs,
@@ -160,14 +160,14 @@ public:
const cmCustomCommandLines& commandLines, const char* comment,
const char* workingDir, bool replace = false, bool escapeOldStyle = true,
bool uses_terminal = false, bool command_expand_lists = false,
- const std::string& depfile = "");
+ const std::string& depfile = "", const std::string& job_pool = "");
cmSourceFile* AddCustomCommandToOutput(
const std::string& output, const std::vector<std::string>& depends,
const std::string& main_dependency,
const cmCustomCommandLines& commandLines, const char* comment,
const char* workingDir, bool replace = false, bool escapeOldStyle = true,
bool uses_terminal = false, bool command_expand_lists = false,
- const std::string& depfile = "");
+ const std::string& depfile = "", const std::string& job_pool = "");
void AddCustomCommandOldStyle(const std::string& target,
const std::vector<std::string>& outputs,
const std::vector<std::string>& depends,
@@ -223,14 +223,14 @@ public:
const char* workingDirectory, const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, bool escapeOldStyle = true,
const char* comment = nullptr, bool uses_terminal = false,
- bool command_expand_lists = false);
+ bool command_expand_lists = false, const std::string& job_pool = "");
cmTarget* AddUtilityCommand(
const std::string& utilityName, TargetOrigin origin, bool excludeFromAll,
const char* workingDirectory, const std::vector<std::string>& byproducts,
const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, bool escapeOldStyle = true,
const char* comment = nullptr, bool uses_terminal = false,
- bool command_expand_lists = false);
+ bool command_expand_lists = false, const std::string& job_pool = "");
/**
* Add a subdirectory to the build.
@@ -257,7 +257,7 @@ public:
* can be used in CMake to refer to lists, directories, etc.
*/
void AddDefinition(const std::string& name, const char* value);
- ///! Add a definition to this makefile and the global cmake cache.
+ //! Add a definition to this makefile and the global cmake cache.
void AddCacheDefinition(const std::string& name, const char* value,
const char* doc, cmStateEnums::CacheEntryType type,
bool force = false);
@@ -272,7 +272,7 @@ public:
* for cache entries, and will only affect the current makefile.
*/
void RemoveDefinition(const std::string& name);
- ///! Remove a definition from the cache.
+ //! Remove a definition from the cache.
void RemoveCacheDefinition(const std::string& name);
/**
@@ -313,6 +313,9 @@ public:
PolicyPushPop(cmMakefile* m);
~PolicyPushPop();
+ PolicyPushPop(const PolicyPushPop&) = delete;
+ PolicyPushPop& operator=(const PolicyPushPop&) = delete;
+
private:
cmMakefile* Makefile;
};
@@ -370,14 +373,13 @@ public:
return this->ComplainFileRegularExpression.c_str();
}
- /**
- * Get the list of targets
- */
- cmTargets& GetTargets() { return this->Targets; }
- /**
- * Get the list of targets, const version
- */
- const cmTargets& GetTargets() const { return this->Targets; }
+ // -- List of targets
+ typedef std::unordered_map<std::string, cmTarget> cmTargetMap;
+ /** Get the target map */
+ cmTargetMap& GetTargets() { return this->Targets; }
+ /** Get the target map - const version */
+ cmTargetMap const& GetTargets() const { return this->Targets; }
+
const std::vector<cmTarget*>& GetOwnedImportedTargets() const
{
return this->ImportedTargetsOwned;
@@ -436,7 +438,7 @@ public:
const char* GetDefinition(const std::string&) const;
const std::string* GetDef(const std::string&) const;
const std::string& GetSafeDefinition(const std::string&) const;
- std::string GetRequiredDefinition(const std::string& name) const;
+ const std::string& GetRequiredDefinition(const std::string& name) const;
bool IsDefinitionSet(const std::string&) const;
/**
* Get the list of all variables in the current space. If argument
@@ -545,7 +547,7 @@ public:
{
return this->ListFiles;
}
- ///! When the file changes cmake will be re-run from the build system.
+ //! When the file changes cmake will be re-run from the build system.
void AddCMakeDependFile(const std::string& file)
{
this->ListFiles.push_back(file);
@@ -607,8 +609,8 @@ public:
/**
* Copy file but change lines according to ConfigureString
*/
- int ConfigureFile(const char* infile, const char* outfile, bool copyonly,
- bool atOnly, bool escapeQuotes,
+ int ConfigureFile(const std::string& infile, const std::string& outfile,
+ bool copyonly, bool atOnly, bool escapeQuotes,
cmNewLineStyle = cmNewLineStyle());
/**
@@ -623,7 +625,7 @@ public:
bool ExecuteCommand(const cmListFileFunction& lff,
cmExecutionStatus& status);
- ///! Enable support for named language, if nil then all languages are
+ //! Enable support for named language, if nil then all languages are
/// enabled.
void EnableLanguage(std::vector<std::string> const& languages,
bool optional);
@@ -638,8 +640,8 @@ public:
cmVariableWatch* GetVariableWatch() const;
#endif
- ///! Display progress or status message.
- void DisplayStatus(const char*, float) const;
+ //! Display progress or status message.
+ void DisplayStatus(const std::string&, float) const;
/**
* Expand the given list file arguments into the full set after
@@ -674,7 +676,7 @@ public:
*/
cmSourceFile* GetSourceFileWithOutput(const std::string& outName) const;
- ///! Add a new cmTest to the list of tests for this makefile.
+ //! Add a new cmTest to the list of tests for this makefile.
cmTest* CreateTest(const std::string& testName);
/** Get a cmTest pointer for a given test name, if the name is
@@ -698,7 +700,7 @@ public:
std::string GetModulesFile(const std::string& name, bool& system) const;
- ///! Set/Get a property of this directory
+ //! Set/Get a property of this directory
void SetProperty(const std::string& prop, const char* value);
void AppendProperty(const std::string& prop, const char* value,
bool asString = false);
@@ -707,7 +709,7 @@ public:
bool GetPropertyAsBool(const std::string& prop) const;
std::vector<std::string> GetPropertyKeys() const;
- ///! Initialize a makefile from its parent
+ //! Initialize a makefile from its parent
void InitializeFromParent(cmMakefile* parent);
void AddInstallGenerator(cmInstallGenerator* g)
@@ -743,6 +745,9 @@ public:
cmPolicies::PolicyMap const& pm);
~FunctionPushPop();
+ FunctionPushPop(const FunctionPushPop&) = delete;
+ FunctionPushPop& operator=(const FunctionPushPop&) = delete;
+
void Quiet() { this->ReportError = false; }
private:
@@ -757,6 +762,9 @@ public:
cmPolicies::PolicyMap const& pm);
~MacroPushPop();
+ MacroPushPop(const MacroPushPop&) = delete;
+ MacroPushPop& operator=(const MacroPushPop&) = delete;
+
void Quiet() { this->ReportError = false; }
private:
@@ -887,7 +895,7 @@ protected:
mutable std::set<cmListFileContext> CMP0054ReportedIds;
// libraries, classes, and executables
- mutable cmTargets Targets;
+ mutable cmTargetMap Targets;
std::map<std::string, std::string> AliasTargets;
typedef std::vector<cmSourceFile*> SourceFileVec;
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index e8ae5ae36..6b9b9c7f1 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -2,13 +2,14 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmMakefileExecutableTargetGenerator.h"
-#include <algorithm>
#include <memory> // IWYU pragma: keep
+#include <set>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
+#include "cmAlgorithms.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalUnixMakefileGenerator3.h"
@@ -31,19 +32,16 @@ cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator(
: cmMakefileTargetGenerator(target)
{
this->CustomCommandDriver = OnDepends;
- this->GeneratorTarget->GetExecutableNames(
- this->TargetNameOut, this->TargetNameReal, this->TargetNameImport,
- this->TargetNamePDB, this->ConfigName);
+ this->TargetNames =
+ this->GeneratorTarget->GetExecutableNames(this->ConfigName);
this->OSXBundleGenerator =
- new cmOSXBundleGenerator(target, this->ConfigName);
+ cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
}
-cmMakefileExecutableTargetGenerator::~cmMakefileExecutableTargetGenerator()
-{
- delete this->OSXBundleGenerator;
-}
+cmMakefileExecutableTargetGenerator::~cmMakefileExecutableTargetGenerator() =
+ default;
void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
{
@@ -84,24 +82,9 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
bool relink)
{
#ifdef CMAKE_BUILD_WITH_CMAKE
- if (!this->GlobalGenerator->GetLanguageEnabled("CUDA")) {
- return;
- }
-
- const std::string cuda_lang("CUDA");
- cmGeneratorTarget::LinkClosure const* closure =
- this->GeneratorTarget->GetLinkClosure(this->ConfigName);
-
- const bool hasCUDA =
- (std::find(closure->Languages.begin(), closure->Languages.end(),
- cuda_lang) != closure->Languages.end());
-
- bool doDeviceLinking = true;
- if (const char* resolveDeviceSymbols =
- this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
- doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
- }
- if (!hasCUDA || !doDeviceLinking) {
+ const bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
+ if (!requiresDeviceLinking) {
return;
}
@@ -109,7 +92,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
// Get the language to use for linking this library.
std::string linkLanguage = "CUDA";
- std::string const objExt =
+ std::string const& objExt =
this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION");
// Build list of dependencies.
@@ -281,7 +264,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
commands1.clear();
// Write the build rule.
@@ -293,8 +276,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
this->WriteTargetDriverRule(targetOutputReal, relink);
// Clean all the possible executable names and symlinks.
- this->CleanFiles.insert(this->CleanFiles.end(), exeCleanFiles.begin(),
- exeCleanFiles.end());
+ this->CleanFiles.insert(exeCleanFiles.begin(), exeCleanFiles.end());
#else
static_cast<void>(relink);
#endif
@@ -305,18 +287,13 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
std::vector<std::string> commands;
// Get the name of the executable to generate.
- std::string targetName;
- std::string targetNameReal;
- std::string targetNameImport;
- std::string targetNamePDB;
- this->GeneratorTarget->GetExecutableNames(targetName, targetNameReal,
- targetNameImport, targetNamePDB,
- this->ConfigName);
+ cmGeneratorTarget::Names targetNames =
+ this->GeneratorTarget->GetExecutableNames(this->ConfigName);
// Construct the full path version of the names.
std::string outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
if (this->GeneratorTarget->IsAppBundleOnApple()) {
- this->OSXBundleGenerator->CreateAppBundle(targetName, outpath);
+ this->OSXBundleGenerator->CreateAppBundle(targetNames.Output, outpath);
}
outpath += "/";
std::string outpathImp;
@@ -326,12 +303,12 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
outpath += "/CMakeRelink.dir";
cmSystemTools::MakeDirectory(outpath);
outpath += "/";
- if (!targetNameImport.empty()) {
+ if (!targetNames.ImportLibrary.empty()) {
outpathImp = outpath;
}
} else {
cmSystemTools::MakeDirectory(outpath);
- if (!targetNameImport.empty()) {
+ if (!targetNames.ImportLibrary.empty()) {
outpathImp = this->GeneratorTarget->GetDirectory(
this->ConfigName, cmStateEnums::ImportLibraryArtifact);
cmSystemTools::MakeDirectory(outpathImp);
@@ -348,10 +325,10 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
cmSystemTools::MakeDirectory(pdbOutputPath);
pdbOutputPath += "/";
- std::string targetFullPath = outpath + targetName;
- std::string targetFullPathReal = outpath + targetNameReal;
- std::string targetFullPathPDB = pdbOutputPath + targetNamePDB;
- std::string targetFullPathImport = outpathImp + targetNameImport;
+ std::string targetFullPath = outpath + targetNames.Output;
+ std::string targetFullPathReal = outpath + targetNames.Real;
+ std::string targetFullPathPDB = pdbOutputPath + targetNames.PDB;
+ std::string targetFullPathImport = outpathImp + targetNames.ImportLibrary;
std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat(
targetFullPathPDB, cmOutputConverter::SHELL);
// Convert to the output path to use in constructing commands.
@@ -376,8 +353,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
// Make sure we have a link language.
if (linkLanguage.empty()) {
- cmSystemTools::Error("Cannot determine link language for target \"",
- this->GeneratorTarget->GetName().c_str(), "\".");
+ cmSystemTools::Error("Cannot determine link language for target \"" +
+ this->GeneratorTarget->GetName() + "\".");
return;
}
@@ -468,11 +445,11 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
this->LocalGenerator->GetCurrentBinaryDirectory(),
targetFullPath + ".manifest"));
#endif
- if (targetNameReal != targetName) {
+ if (this->TargetNames.Real != this->TargetNames.Output) {
exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal));
}
- if (!targetNameImport.empty()) {
+ if (!this->TargetNames.ImportLibrary.empty()) {
exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(),
targetFullPathImport));
@@ -487,7 +464,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
// List the PDB for cleaning only when the whole target is
// cleaned. We do not want to delete the .pdb file just before
// linking the target.
- this->CleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->CleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathPDB));
// Add the pre-build and pre-link rules building but not when relinking.
@@ -657,7 +634,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
commands1.clear();
// Add a rule to create necessary symlinks for the library.
@@ -670,7 +647,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
commands1.clear();
}
@@ -702,6 +679,5 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
this->WriteTargetDriverRule(targetFullPath, relink);
// Clean all the possible executable names and symlinks.
- this->CleanFiles.insert(this->CleanFiles.end(), exeCleanFiles.begin(),
- exeCleanFiles.end());
+ this->CleanFiles.insert(exeCleanFiles.begin(), exeCleanFiles.end());
}
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index 5a1ef4efe..b9f7c6d13 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -2,13 +2,14 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmMakefileLibraryTargetGenerator.h"
-#include <algorithm>
#include <memory> // IWYU pragma: keep
+#include <set>
#include <sstream>
#include <stddef.h>
#include <utility>
#include <vector>
+#include "cmAlgorithms.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalUnixMakefileGenerator3.h"
@@ -32,20 +33,17 @@ cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator(
{
this->CustomCommandDriver = OnDepends;
if (this->GeneratorTarget->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
- this->GeneratorTarget->GetLibraryNames(
- this->TargetNameOut, this->TargetNameSO, this->TargetNameReal,
- this->TargetNameImport, this->TargetNamePDB, this->ConfigName);
+ this->TargetNames =
+ this->GeneratorTarget->GetLibraryNames(this->ConfigName);
}
this->OSXBundleGenerator =
- new cmOSXBundleGenerator(target, this->ConfigName);
+ cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
}
-cmMakefileLibraryTargetGenerator::~cmMakefileLibraryTargetGenerator()
-{
- delete this->OSXBundleGenerator;
-}
+cmMakefileLibraryTargetGenerator::~cmMakefileLibraryTargetGenerator() =
+ default;
void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
{
@@ -125,20 +123,9 @@ void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules()
void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
{
- const std::string cuda_lang("CUDA");
- cmGeneratorTarget::LinkClosure const* closure =
- this->GeneratorTarget->GetLinkClosure(this->ConfigName);
-
- const bool hasCUDA =
- (std::find(closure->Languages.begin(), closure->Languages.end(),
- cuda_lang) != closure->Languages.end());
-
- bool doDeviceLinking = false;
- if (const char* resolveDeviceSymbols =
- this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
- doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
- }
- if (hasCUDA && doDeviceLinking) {
+ const bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
+ if (requiresDeviceLinking) {
std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
this->WriteDeviceLibraryRules(linkRuleVar, false);
}
@@ -164,19 +151,9 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
}
if (!relink) {
- const std::string cuda_lang("CUDA");
- cmGeneratorTarget::LinkClosure const* closure =
- this->GeneratorTarget->GetLinkClosure(this->ConfigName);
-
- const bool hasCUDA =
- (std::find(closure->Languages.begin(), closure->Languages.end(),
- cuda_lang) != closure->Languages.end());
- bool doDeviceLinking = true;
- if (const char* resolveDeviceSymbols =
- this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
- doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
- }
- if (hasCUDA && doDeviceLinking) {
+ const bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
+ if (requiresDeviceLinking) {
std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
this->WriteDeviceLibraryRules(linkRuleVar, relink);
}
@@ -208,21 +185,10 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
{
-
if (!relink) {
- const std::string cuda_lang("CUDA");
- cmGeneratorTarget::LinkClosure const* closure =
- this->GeneratorTarget->GetLinkClosure(this->ConfigName);
-
- const bool hasCUDA =
- (std::find(closure->Languages.begin(), closure->Languages.end(),
- cuda_lang) != closure->Languages.end());
- bool doDeviceLinking = true;
- if (const char* resolveDeviceSymbols =
- this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
- doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
- }
- if (hasCUDA && doDeviceLinking) {
+ const bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
+ if (requiresDeviceLinking) {
std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
this->WriteDeviceLibraryRules(linkRuleVar, relink);
}
@@ -306,8 +272,8 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress);
}
// Clean files associated with this library.
- std::vector<std::string> libCleanFiles;
- libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ std::set<std::string> libCleanFiles;
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutputReal));
// Determine whether a link script will be used.
@@ -414,8 +380,7 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
this->LocalGenerator->SetLinkScriptShell(false);
// Clean all the possible library names and symlinks.
- this->CleanFiles.insert(this->CleanFiles.end(), libCleanFiles.begin(),
- libCleanFiles.end());
+ this->CleanFiles.insert(libCleanFiles.begin(), libCleanFiles.end());
}
std::vector<std::string> commands1;
@@ -432,7 +397,7 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
commands1.clear();
// Compute the list of outputs.
@@ -463,8 +428,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
// Make sure we have a link language.
if (linkLanguage.empty()) {
- cmSystemTools::Error("Cannot determine link language for target \"",
- this->GeneratorTarget->GetName().c_str(), "\".");
+ cmSystemTools::Error("Cannot determine link language for target \"" +
+ this->GeneratorTarget->GetName() + "\".");
return;
}
@@ -489,25 +454,20 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
}
// Construct the name of the library.
- std::string targetName;
- std::string targetNameSO;
- std::string targetNameReal;
- std::string targetNameImport;
- std::string targetNamePDB;
- this->GeneratorTarget->GetLibraryNames(targetName, targetNameSO,
- targetNameReal, targetNameImport,
- targetNamePDB, this->ConfigName);
+ this->GeneratorTarget->GetLibraryNames(this->ConfigName);
// Construct the full path version of the names.
std::string outpath;
std::string outpathImp;
if (this->GeneratorTarget->IsFrameworkOnApple()) {
outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
- this->OSXBundleGenerator->CreateFramework(targetName, outpath);
+ this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output,
+ outpath);
outpath += "/";
} else if (this->GeneratorTarget->IsCFBundleOnApple()) {
outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
- this->OSXBundleGenerator->CreateCFBundle(targetName, outpath);
+ this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output,
+ outpath);
outpath += "/";
} else if (relink) {
outpath = this->Makefile->GetCurrentBinaryDirectory();
@@ -515,14 +475,14 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
outpath += "/CMakeRelink.dir";
cmSystemTools::MakeDirectory(outpath);
outpath += "/";
- if (!targetNameImport.empty()) {
+ if (!this->TargetNames.ImportLibrary.empty()) {
outpathImp = outpath;
}
} else {
outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
cmSystemTools::MakeDirectory(outpath);
outpath += "/";
- if (!targetNameImport.empty()) {
+ if (!this->TargetNames.ImportLibrary.empty()) {
outpathImp = this->GeneratorTarget->GetDirectory(
this->ConfigName, cmStateEnums::ImportLibraryArtifact);
cmSystemTools::MakeDirectory(outpathImp);
@@ -539,11 +499,12 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
cmSystemTools::MakeDirectory(pdbOutputPath);
pdbOutputPath += "/";
- std::string targetFullPath = outpath + targetName;
- std::string targetFullPathPDB = pdbOutputPath + targetNamePDB;
- std::string targetFullPathSO = outpath + targetNameSO;
- std::string targetFullPathReal = outpath + targetNameReal;
- std::string targetFullPathImport = outpathImp + targetNameImport;
+ std::string targetFullPath = outpath + this->TargetNames.Output;
+ std::string targetFullPathPDB = pdbOutputPath + this->TargetNames.PDB;
+ std::string targetFullPathSO = outpath + this->TargetNames.SharedObject;
+ std::string targetFullPathReal = outpath + this->TargetNames.Real;
+ std::string targetFullPathImport =
+ outpathImp + this->TargetNames.ImportLibrary;
// Construct the output path version of the names for use in command
// arguments.
@@ -599,8 +560,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
}
// Clean files associated with this library.
- std::vector<std::string> libCleanFiles;
- libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ std::set<std::string> libCleanFiles;
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal));
std::vector<std::string> commands1;
@@ -612,26 +573,27 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
commands1.clear();
}
- if (targetName != targetNameReal) {
- libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ if (this->TargetNames.Output != this->TargetNames.Real) {
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPath));
}
- if (targetNameSO != targetNameReal && targetNameSO != targetName) {
- libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ if (this->TargetNames.SharedObject != this->TargetNames.Real &&
+ this->TargetNames.SharedObject != this->TargetNames.Output) {
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathSO));
}
- if (!targetNameImport.empty()) {
- libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ if (!this->TargetNames.ImportLibrary.empty()) {
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(),
targetFullPathImport));
std::string implib;
if (this->GeneratorTarget->GetImplibGNUtoMS(
this->ConfigName, targetFullPathImport, implib)) {
- libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), implib));
}
}
@@ -639,14 +601,14 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
// List the PDB for cleaning only when the whole target is
// cleaned. We do not want to delete the .pdb file just before
// linking the target.
- this->CleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->CleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathPDB));
#ifdef _WIN32
// There may be a manifest file for this target. Add it to the
// clean set just in case.
if (this->GeneratorTarget->GetType() != cmStateEnums::STATIC_LIBRARY) {
- libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
+ libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(),
targetFullPath + ".manifest"));
}
@@ -820,7 +782,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
vars.ObjectsQuoted = buildObjs.c_str();
if (this->GeneratorTarget->HasSOName(this->ConfigName)) {
vars.SONameFlag = this->Makefile->GetSONameFlag(linkLanguage);
- vars.TargetSOName = targetNameSO.c_str();
+ vars.TargetSOName = this->TargetNames.SharedObject.c_str();
}
vars.LinkFlags = linkFlags.c_str();
@@ -951,7 +913,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
commands1.clear();
// Add a rule to create necessary symlinks for the library.
@@ -968,7 +930,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), commands1.begin(), commands1.end());
+ cmAppend(commands, commands1);
commands1.clear();
}
@@ -981,10 +943,11 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
// Compute the list of outputs.
std::vector<std::string> outputs(1, targetFullPathReal);
- if (targetNameSO != targetNameReal) {
+ if (this->TargetNames.SharedObject != this->TargetNames.Real) {
outputs.push_back(targetFullPathSO);
}
- if (targetName != targetNameSO && targetName != targetNameReal) {
+ if (this->TargetNames.Output != this->TargetNames.SharedObject &&
+ this->TargetNames.Output != this->TargetNames.Real) {
outputs.push_back(targetFullPath);
}
@@ -996,6 +959,5 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
this->WriteTargetDriverRule(targetFullPath, relink);
// Clean all the possible library names and symlinks.
- this->CleanFiles.insert(this->CleanFiles.end(), libCleanFiles.begin(),
- libCleanFiles.end());
+ this->CleanFiles.insert(libCleanFiles.begin(), libCleanFiles.end());
}
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index af34169c3..b3bab4b08 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -21,6 +21,7 @@
#include "cmMakefileLibraryTargetGenerator.h"
#include "cmMakefileUtilityTargetGenerator.h"
#include "cmOutputConverter.h"
+#include "cmRange.h"
#include "cmRulePlaceholderExpander.h"
#include "cmSourceFile.h"
#include "cmState.h"
@@ -146,21 +147,41 @@ void cmMakefileTargetGenerator::CreateRuleFile()
void cmMakefileTargetGenerator::WriteTargetBuildRules()
{
+ // -- Write the custom commands for this target
+
const std::string& config =
this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
- // write the custom commands for this target
- // Look for files registered for cleaning in this directory.
- if (const char* additional_clean_files =
- this->Makefile->GetProperty("ADDITIONAL_MAKE_CLEAN_FILES")) {
+ // Evaluates generator expressions and expands prop_value
+ auto evaluatedFiles =
+ [this, &config](const char* prop_value) -> std::vector<std::string> {
+ std::vector<std::string> files;
cmGeneratorExpression ge;
- std::unique_ptr<cmCompiledGeneratorExpression> cge =
- ge.Parse(additional_clean_files);
-
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop_value);
cmSystemTools::ExpandListArgument(
cge->Evaluate(this->LocalGenerator, config, false, this->GeneratorTarget,
nullptr, nullptr),
- this->CleanFiles);
+ files);
+ return files;
+ };
+
+ // Look for additional files registered for cleaning in this directory.
+ if (const char* prop_value =
+ this->Makefile->GetProperty("ADDITIONAL_MAKE_CLEAN_FILES")) {
+ std::vector<std::string> const files = evaluatedFiles(prop_value);
+ this->CleanFiles.insert(files.begin(), files.end());
+ }
+
+ // Look for additional files registered for cleaning in this target.
+ if (const char* prop_value =
+ this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) {
+ std::vector<std::string> const files = evaluatedFiles(prop_value);
+ // For relative path support
+ std::string const& binaryDir =
+ this->LocalGenerator->GetCurrentBinaryDirectory();
+ for (std::string const& cfl : files) {
+ this->CleanFiles.insert(cmSystemTools::CollapseFullPath(cfl, binaryDir));
+ }
}
// add custom commands to the clean rules?
@@ -180,13 +201,13 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
if (clean) {
const std::vector<std::string>& outputs = ccg.GetOutputs();
for (std::string const& output : outputs) {
- this->CleanFiles.push_back(
+ this->CleanFiles.insert(
this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir,
output));
}
const std::vector<std::string>& byproducts = ccg.GetByproducts();
for (std::string const& byproduct : byproducts) {
- this->CleanFiles.push_back(
+ this->CleanFiles.insert(
this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir,
byproduct));
}
@@ -198,19 +219,14 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
std::vector<cmCustomCommand> buildEventCommands =
this->GeneratorTarget->GetPreBuildCommands();
- buildEventCommands.insert(
- buildEventCommands.end(),
- this->GeneratorTarget->GetPreLinkCommands().begin(),
- this->GeneratorTarget->GetPreLinkCommands().end());
- buildEventCommands.insert(
- buildEventCommands.end(),
- this->GeneratorTarget->GetPostBuildCommands().begin(),
- this->GeneratorTarget->GetPostBuildCommands().end());
+ cmAppend(buildEventCommands, this->GeneratorTarget->GetPreLinkCommands());
+ cmAppend(buildEventCommands,
+ this->GeneratorTarget->GetPostBuildCommands());
for (const auto& be : buildEventCommands) {
const std::vector<std::string>& byproducts = be.GetByproducts();
for (std::string const& byproduct : byproducts) {
- this->CleanFiles.push_back(
+ this->CleanFiles.insert(
this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir,
byproduct));
}
@@ -349,7 +365,7 @@ void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()(
std::string output = macdir;
output += "/";
output += cmSystemTools::GetFilenameName(input);
- this->Generator->CleanFiles.push_back(
+ this->Generator->CleanFiles.insert(
this->Generator->LocalGenerator->MaybeConvertToRelativePath(
this->Generator->LocalGenerator->GetCurrentBinaryDirectory(), output));
output = this->Generator->LocalGenerator->MaybeConvertToRelativePath(
@@ -414,7 +430,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
// Save this in the target's list of object files.
this->Objects.push_back(obj);
- this->CleanFiles.push_back(obj);
+ this->CleanFiles.insert(obj);
// TODO: Remove
// std::string relativeObj
@@ -654,19 +670,20 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
std::string cmdVar;
if (this->GeneratorTarget->GetPropertyAsBool(
"CUDA_SEPARABLE_COMPILATION")) {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION";
} else if (this->GeneratorTarget->GetPropertyAsBool(
"CUDA_PTX_COMPILATION")) {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_PTX_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION";
} else {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_WHOLE_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION";
}
- std::string compileRule = this->Makefile->GetRequiredDefinition(cmdVar);
+ const std::string& compileRule =
+ this->Makefile->GetRequiredDefinition(cmdVar);
cmSystemTools::ExpandListArgument(compileRule, compileCommands);
} else {
- const std::string cmdVar =
- std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
- std::string compileRule = this->Makefile->GetRequiredDefinition(cmdVar);
+ const std::string cmdVar = "CMAKE_" + lang + "_COMPILE_OBJECT";
+ const std::string& compileRule =
+ this->Makefile->GetRequiredDefinition(cmdVar);
cmSystemTools::ExpandListArgument(compileRule, compileCommands);
}
@@ -766,8 +783,12 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
if (!compileCommands.empty() && !compilerLauncher.empty()) {
std::vector<std::string> args;
cmSystemTools::ExpandListArgument(compilerLauncher, args, true);
- for (std::string& i : args) {
- i = this->LocalGenerator->EscapeForShell(i);
+ if (!args.empty()) {
+ args[0] = this->LocalGenerator->ConvertToOutputFormat(
+ args[0], cmOutputConverter::SHELL);
+ for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) {
+ i = this->LocalGenerator->EscapeForShell(i);
+ }
}
compileCommands.front().insert(0, cmJoin(args, " ") + " ");
}
@@ -793,8 +814,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
this->LocalGenerator->CreateCDCommand(
compileCommands, this->LocalGenerator->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), compileCommands.begin(),
- compileCommands.end());
+ cmAppend(commands, compileCommands);
}
// Check for extra outputs created by the compilation.
@@ -802,8 +822,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
if (const char* extra_outputs_str = source.GetProperty("OBJECT_OUTPUTS")) {
// Register these as extra files to clean.
cmSystemTools::ExpandListArgument(extra_outputs_str, outputs);
- this->CleanFiles.insert(this->CleanFiles.end(), outputs.begin() + 1,
- outputs.end());
+ this->CleanFiles.insert(outputs.begin() + 1, outputs.end());
}
// Write the rule.
@@ -857,8 +876,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
preprocessCommands,
this->LocalGenerator->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), preprocessCommands.begin(),
- preprocessCommands.end());
+ cmAppend(commands, preprocessCommands);
} else {
std::string cmd = "$(CMAKE_COMMAND) -E cmake_unimplemented_variable ";
cmd += preprocessRuleVar;
@@ -904,8 +922,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile(
this->LocalGenerator->CreateCDCommand(
assemblyCommands, this->LocalGenerator->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
- commands.insert(commands.end(), assemblyCommands.begin(),
- assemblyCommands.end());
+ cmAppend(commands, assemblyCommands);
} else {
std::string cmd = "$(CMAKE_COMMAND) -E cmake_unimplemented_variable ";
cmd += assemblyRuleVar;
@@ -974,18 +991,17 @@ bool cmMakefileTargetGenerator::WriteMakeRule(
// For multiple outputs, make the extra ones depend on the first one.
std::vector<std::string> const output_depends(1, outputs[0]);
std::string binDir = this->LocalGenerator->GetBinaryDirectory();
- for (std::vector<std::string>::const_iterator o = outputs.begin() + 1;
- o != outputs.end(); ++o) {
+ for (std::string const& output : cmMakeRange(outputs).advance(1)) {
// Touch the extra output so "make" knows that it was updated,
// but only if the output was actually created.
std::string const out = this->LocalGenerator->ConvertToOutputFormat(
- this->LocalGenerator->MaybeConvertToRelativePath(binDir, *o),
+ this->LocalGenerator->MaybeConvertToRelativePath(binDir, output),
cmOutputConverter::SHELL);
std::vector<std::string> output_commands;
bool o_symbolic = false;
if (need_symbolic) {
- if (cmSourceFile* sf = this->Makefile->GetSource(*o)) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(output)) {
o_symbolic = sf->GetPropertyAsBool("SYMBOLIC");
}
}
@@ -994,13 +1010,13 @@ bool cmMakefileTargetGenerator::WriteMakeRule(
if (!o_symbolic) {
output_commands.push_back("@$(CMAKE_COMMAND) -E touch_nocreate " + out);
}
- this->LocalGenerator->WriteMakeRule(os, nullptr, *o, output_depends,
+ this->LocalGenerator->WriteMakeRule(os, nullptr, output, output_depends,
output_commands, o_symbolic, in_help);
if (!o_symbolic) {
// At build time, remove the first output if this one does not exist
// so that "make" will rerun the real commands that create this one.
- MultipleOutputPairsType::value_type p(*o, outputs[0]);
+ MultipleOutputPairsType::value_type p(output, outputs[0]);
this->MultipleOutputPairs.insert(p);
}
}
@@ -1153,8 +1169,7 @@ void cmMakefileTargetGenerator::DriveCustomCommands(
if (cmCustomCommand* cc = source->GetCustomCommand()) {
cmCustomCommandGenerator ccg(*cc, this->ConfigName,
this->LocalGenerator);
- const std::vector<std::string>& outputs = ccg.GetOutputs();
- depends.insert(depends.end(), outputs.begin(), outputs.end());
+ cmAppend(depends, ccg.GetOutputs());
}
}
}
@@ -1378,8 +1393,7 @@ void cmMakefileTargetGenerator::WriteTargetDriverRule(
}
// Make sure the extra files are built.
- depends.insert(depends.end(), this->ExtraFiles.begin(),
- this->ExtraFiles.end());
+ cmAppend(depends, this->ExtraFiles);
}
// Write the driver rule.
@@ -1398,11 +1412,10 @@ void cmMakefileTargetGenerator::AppendTargetDepends(
}
// Loop over all library dependencies.
- const char* cfg = this->LocalGenerator->GetConfigName().c_str();
+ const std::string& cfg = this->LocalGenerator->GetConfigName();
if (cmComputeLinkInformation* cli =
this->GeneratorTarget->GetLinkInformation(cfg)) {
- std::vector<std::string> const& libDeps = cli->GetDepends();
- depends.insert(depends.end(), libDeps.begin(), libDeps.end());
+ cmAppend(depends, cli->GetDepends());
}
}
@@ -1419,8 +1432,7 @@ void cmMakefileTargetGenerator::AppendObjectDepends(
}
// Add dependencies on the external object files.
- depends.insert(depends.end(), this->ExternalObjects.begin(),
- this->ExternalObjects.end());
+ cmAppend(depends, this->ExternalObjects);
// Add a dependency on the rule file itself.
this->LocalGenerator->AppendRuleDepend(depends,
@@ -1603,7 +1615,8 @@ void cmMakefileTargetGenerator::CreateLinkLibs(
{
std::string frameworkPath;
std::string linkPath;
- std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ const std::string& config =
+ this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
cmComputeLinkInformation* pcli =
this->GeneratorTarget->GetLinkInformation(config);
this->LocalGenerator->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
index 529b4db44..c570a7ccf 100644
--- a/Source/cmMakefileTargetGenerator.h
+++ b/Source/cmMakefileTargetGenerator.h
@@ -12,12 +12,12 @@
#include <vector>
#include "cmCommonTargetGenerator.h"
+#include "cmGeneratorTarget.h"
#include "cmLocalUnixMakefileGenerator3.h"
#include "cmOSXBundleGenerator.h"
class cmCustomCommandGenerator;
class cmGeneratedFileStream;
-class cmGeneratorTarget;
class cmGlobalUnixMakefileGenerator3;
class cmLinkLineComputer;
class cmOutputConverter;
@@ -210,7 +210,7 @@ protected:
cmGeneratedFileStream* InfoFileStream;
// files to clean
- std::vector<std::string> CleanFiles;
+ std::set<std::string> CleanFiles;
// objects used by this target
std::vector<std::string> Objects;
@@ -231,15 +231,11 @@ protected:
bool in_help = false);
// Target name info.
- std::string TargetNameOut;
- std::string TargetNameSO;
- std::string TargetNameReal;
- std::string TargetNameImport;
- std::string TargetNamePDB;
+ cmGeneratorTarget::Names TargetNames;
// macOS content info.
std::set<std::string> MacContentFolders;
- cmOSXBundleGenerator* OSXBundleGenerator;
+ std::unique_ptr<cmOSXBundleGenerator> OSXBundleGenerator;
MacOSXContentGeneratorType* MacOSXContentGenerator;
};
diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx
index 8fbd5d2bd..42369954c 100644
--- a/Source/cmMakefileUtilityTargetGenerator.cxx
+++ b/Source/cmMakefileUtilityTargetGenerator.cxx
@@ -7,6 +7,7 @@
#include <utility>
#include <vector>
+#include "cmAlgorithms.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalUnixMakefileGenerator3.h"
@@ -21,14 +22,12 @@ cmMakefileUtilityTargetGenerator::cmMakefileUtilityTargetGenerator(
{
this->CustomCommandDriver = OnUtility;
this->OSXBundleGenerator =
- new cmOSXBundleGenerator(target, this->ConfigName);
+ cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
}
-cmMakefileUtilityTargetGenerator::~cmMakefileUtilityTargetGenerator()
-{
- delete this->OSXBundleGenerator;
-}
+cmMakefileUtilityTargetGenerator::~cmMakefileUtilityTargetGenerator() =
+ default;
void cmMakefileUtilityTargetGenerator::WriteRuleFiles()
{
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
index 95f5fcbbe..5320ec570 100644
--- a/Source/cmMessageCommand.cxx
+++ b/Source/cmMessageCommand.cxx
@@ -6,7 +6,11 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmMessenger.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cassert>
class cmExecutionStatus;
@@ -18,49 +22,88 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args,
this->SetError("called with incorrect number of arguments");
return false;
}
- std::vector<std::string>::const_iterator i = args.begin();
+ auto i = args.cbegin();
- MessageType type = MessageType::MESSAGE;
- bool status = false;
- bool fatal = false;
+ auto type = MessageType::MESSAGE;
+ auto status = false;
+ auto fatal = false;
+ auto level = cmake::LogLevel::LOG_UNDEFINED;
if (*i == "SEND_ERROR") {
type = MessageType::FATAL_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
++i;
} else if (*i == "FATAL_ERROR") {
fatal = true;
type = MessageType::FATAL_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
++i;
} else if (*i == "WARNING") {
type = MessageType::WARNING;
+ level = cmake::LogLevel::LOG_WARNING;
++i;
} else if (*i == "AUTHOR_WARNING") {
if (this->Makefile->IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") &&
!this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) {
fatal = true;
type = MessageType::AUTHOR_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
} else if (!this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
type = MessageType::AUTHOR_WARNING;
+ level = cmake::LogLevel::LOG_WARNING;
} else {
return true;
}
++i;
} else if (*i == "STATUS") {
status = true;
+ level = cmake::LogLevel::LOG_STATUS;
+ ++i;
+ } else if (*i == "VERBOSE") {
+ status = true;
+ level = cmake::LogLevel::LOG_VERBOSE;
+ ++i;
+ } else if (*i == "DEBUG") {
+ status = true;
+ level = cmake::LogLevel::LOG_DEBUG;
+ ++i;
+ } else if (*i == "TRACE") {
+ status = true;
+ level = cmake::LogLevel::LOG_TRACE;
++i;
} else if (*i == "DEPRECATION") {
if (this->Makefile->IsOn("CMAKE_ERROR_DEPRECATED")) {
fatal = true;
type = MessageType::DEPRECATION_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
} else if ((!this->Makefile->IsSet("CMAKE_WARN_DEPRECATED") ||
this->Makefile->IsOn("CMAKE_WARN_DEPRECATED"))) {
type = MessageType::DEPRECATION_WARNING;
+ level = cmake::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;
+ ++i;
+ } else {
+ // Messages w/o any type are `NOTICE`s
+ level = cmake::LogLevel::LOG_NOTICE;
+ }
+ assert("Message log level expected to be set" &&
+ level != cmake::LogLevel::LOG_UNDEFINED);
+
+ auto desiredLevel = this->Makefile->GetCMakeInstance()->GetLogLevel();
+ assert("Expected a valid log level here" &&
+ desiredLevel != cmake::LogLevel::LOG_UNDEFINED);
+
+ if (desiredLevel < level) {
+ // Suppress the message
+ return true;
}
- std::string message = cmJoin(cmMakeRange(i, args.end()), std::string());
+ auto message = cmJoin(cmMakeRange(i, args.cend()), "");
if (type != MessageType::MESSAGE) {
// we've overridden the message type, above, so display it directly
@@ -68,7 +111,7 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args,
m->DisplayMessage(type, message, this->Makefile->GetBacktrace());
} else {
if (status) {
- this->Makefile->DisplayStatus(message.c_str(), -1);
+ this->Makefile->DisplayStatus(message, -1);
} else {
cmSystemTools::Message(message);
}
diff --git a/Source/cmNinjaLinkLineDeviceComputer.cxx b/Source/cmNinjaLinkLineDeviceComputer.cxx
new file mode 100644
index 000000000..84c1b37d3
--- /dev/null
+++ b/Source/cmNinjaLinkLineDeviceComputer.cxx
@@ -0,0 +1,20 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmNinjaLinkLineDeviceComputer.h"
+
+#include "cmGlobalNinjaGenerator.h"
+
+cmNinjaLinkLineDeviceComputer::cmNinjaLinkLineDeviceComputer(
+ cmOutputConverter* outputConverter, cmStateDirectory const& stateDir,
+ cmGlobalNinjaGenerator const* gg)
+ : cmLinkLineDeviceComputer(outputConverter, stateDir)
+ , GG(gg)
+{
+}
+
+std::string cmNinjaLinkLineDeviceComputer::ConvertToLinkReference(
+ std::string const& lib) const
+{
+ return GG->ConvertToNinjaPath(lib);
+}
diff --git a/Source/cmNinjaLinkLineDeviceComputer.h b/Source/cmNinjaLinkLineDeviceComputer.h
new file mode 100644
index 000000000..84ced5b35
--- /dev/null
+++ b/Source/cmNinjaLinkLineDeviceComputer.h
@@ -0,0 +1,34 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cmNinjaLinkLineDeviceComputer_h
+#define cmNinjaLinkLineDeviceComputer_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+
+#include "cmLinkLineDeviceComputer.h"
+
+class cmGlobalNinjaGenerator;
+class cmOutputConverter;
+class cmStateDirectory;
+
+class cmNinjaLinkLineDeviceComputer : public cmLinkLineDeviceComputer
+{
+public:
+ cmNinjaLinkLineDeviceComputer(cmOutputConverter* outputConverter,
+ cmStateDirectory const& stateDir,
+ cmGlobalNinjaGenerator const* gg);
+
+ cmNinjaLinkLineDeviceComputer(cmNinjaLinkLineDeviceComputer const&) = delete;
+ cmNinjaLinkLineDeviceComputer& operator=(
+ cmNinjaLinkLineDeviceComputer const&) = delete;
+
+ std::string ConvertToLinkReference(std::string const& input) const override;
+
+private:
+ cmGlobalNinjaGenerator const* GG;
+};
+
+#endif
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index becc42433..f65abc839 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -12,6 +12,7 @@
#include <utility>
#include "cmAlgorithms.h"
+#include "cmCustomCommand.h" // IWYU pragma: keep
#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
@@ -21,6 +22,7 @@
#include "cmLocalGenerator.h"
#include "cmLocalNinjaGenerator.h"
#include "cmMakefile.h"
+#include "cmNinjaLinkLineDeviceComputer.h"
#include "cmNinjaTypes.h"
#include "cmOSXBundleGenerator.h"
#include "cmOutputConverter.h"
@@ -32,8 +34,6 @@
#include "cmStateTypes.h"
#include "cmSystemTools.h"
-class cmCustomCommand;
-
cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
cmGeneratorTarget* target)
: cmNinjaTargetGenerator(target)
@@ -41,13 +41,10 @@ cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
{
this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName());
if (target->GetType() == cmStateEnums::EXECUTABLE) {
- this->GetGeneratorTarget()->GetExecutableNames(
- this->TargetNameOut, this->TargetNameReal, this->TargetNameImport,
- this->TargetNamePDB, GetLocalGenerator()->GetConfigName());
+ this->TargetNames = this->GetGeneratorTarget()->GetExecutableNames(
+ GetLocalGenerator()->GetConfigName());
} else {
- this->GetGeneratorTarget()->GetLibraryNames(
- this->TargetNameOut, this->TargetNameSO, this->TargetNameReal,
- this->TargetNameImport, this->TargetNamePDB,
+ this->TargetNames = this->GetGeneratorTarget()->GetLibraryNames(
GetLocalGenerator()->GetConfigName());
}
@@ -58,21 +55,18 @@ cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
}
this->OSXBundleGenerator =
- new cmOSXBundleGenerator(target, this->GetConfigName());
+ cm::make_unique<cmOSXBundleGenerator>(target, this->GetConfigName());
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
}
-cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator()
-{
- delete this->OSXBundleGenerator;
-}
+cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator() = default;
void cmNinjaNormalTargetGenerator::Generate()
{
if (this->TargetLinkLanguage.empty()) {
cmSystemTools::Error("CMake can not determine linker language for "
- "target: ",
- this->GetGeneratorTarget()->GetName().c_str());
+ "target: " +
+ this->GetGeneratorTarget()->GetName());
return;
}
@@ -90,6 +84,8 @@ void cmNinjaNormalTargetGenerator::Generate()
this->WriteDeviceLinkStatement();
this->WriteLinkStatement();
}
+
+ this->AdditionalCleanFiles();
}
void cmNinjaNormalTargetGenerator::WriteLanguagesRules()
@@ -166,13 +162,8 @@ struct cmNinjaRemoveNoOpCommands
void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile)
{
- cmStateEnums::TargetType targetType = this->GetGeneratorTarget()->GetType();
- std::string ruleName = this->LanguageLinkerDeviceRule();
- // Select whether to use a response file for objects.
- std::string rspfile;
- std::string rspcontent;
-
- if (!this->GetGlobalGenerator()->HasRule(ruleName)) {
+ cmNinjaRule rule(this->LanguageLinkerDeviceRule());
+ if (!this->GetGlobalGenerator()->HasRule(rule.Name)) {
cmRulePlaceholderExpander::RuleVariables vars;
vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
vars.CMTargetType =
@@ -180,32 +171,24 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile)
vars.Language = "CUDA";
- std::string responseFlag;
- if (!useResponseFile) {
+ // build response file name
+ std::string responseFlag = this->GetMakefile()->GetSafeDefinition(
+ "CMAKE_CUDA_RESPONSE_FILE_LINK_FLAG");
+
+ if (!useResponseFile || responseFlag.empty()) {
vars.Objects = "$in";
vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
} else {
- std::string cmakeVarLang = "CMAKE_";
- cmakeVarLang += this->TargetLinkLanguage;
-
- // build response file name
- std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
- const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar);
- if (flag) {
- responseFlag = flag;
- } else {
- responseFlag = "@";
- }
- rspfile = "$RSP_FILE";
- responseFlag += rspfile;
+ rule.RspFile = "$RSP_FILE";
+ responseFlag += rule.RspFile;
// build response file content
if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
- rspcontent = "$in";
+ rule.RspContent = "$in";
} else {
- rspcontent = "$in_newline";
+ rule.RspContent = "$in_newline";
}
- rspcontent += " $LINK_LIBRARIES";
+ rule.RspContent += " $LINK_LIBRARIES";
vars.Objects = responseFlag.c_str();
vars.LinkLibraries = "";
}
@@ -224,7 +207,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile)
vars.Manifests = "$MANIFESTS";
std::string langFlags;
- if (targetType != cmStateEnums::EXECUTABLE) {
+ if (this->GetGeneratorTarget()->GetType() != cmStateEnums::EXECUTABLE) {
langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS";
vars.LanguageCompileFlags = langFlags.c_str();
}
@@ -251,69 +234,84 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile)
// If there is no ranlib the command will be ":". Skip it.
cmEraseIf(linkCmds, cmNinjaRemoveNoOpCommands());
- std::string linkCmd =
- this->GetLocalGenerator()->BuildCommandLine(linkCmds);
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(linkCmds);
// Write the linker rule with response file if needed.
- std::ostringstream comment;
- comment << "Rule for linking " << this->TargetLinkLanguage << " "
- << this->GetVisibleTypeName() << ".";
- std::ostringstream description;
- description << "Linking " << this->TargetLinkLanguage << " "
- << this->GetVisibleTypeName() << " $TARGET_FILE";
- this->GetGlobalGenerator()->AddRule(ruleName, linkCmd, description.str(),
- comment.str(),
- /*depfile*/ "",
- /*deptype*/ "", rspfile, rspcontent,
- /*restat*/ "$RESTAT",
- /*generator*/ false);
+ rule.Comment = "Rule for linking ";
+ rule.Comment += this->TargetLinkLanguage;
+ rule.Comment += " ";
+ rule.Comment += this->GetVisibleTypeName();
+ rule.Comment += ".";
+ rule.Description = "Linking ";
+ rule.Description += this->TargetLinkLanguage;
+ rule.Description += " ";
+ rule.Description += this->GetVisibleTypeName();
+ rule.Description += " $TARGET_FILE";
+ rule.Restat = "$RESTAT";
+
+ this->GetGlobalGenerator()->AddRule(rule);
}
}
void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile)
{
cmStateEnums::TargetType targetType = this->GetGeneratorTarget()->GetType();
- std::string ruleName = this->LanguageLinkerRule();
- // Select whether to use a response file for objects.
- std::string rspfile;
- std::string rspcontent;
-
- if (!this->GetGlobalGenerator()->HasRule(ruleName)) {
+ std::string linkRuleName = this->LanguageLinkerRule();
+ if (!this->GetGlobalGenerator()->HasRule(linkRuleName)) {
+ cmNinjaRule rule(std::move(linkRuleName));
cmRulePlaceholderExpander::RuleVariables vars;
vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
- vars.CMTargetType =
- cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType());
+ vars.CMTargetType = cmState::GetTargetTypeName(targetType);
vars.Language = this->TargetLinkLanguage.c_str();
+ if (this->TargetLinkLanguage == "Swift") {
+ vars.SwiftLibraryName = "$SWIFT_LIBRARY_NAME";
+ vars.SwiftModule = "$SWIFT_MODULE";
+ vars.SwiftModuleName = "$SWIFT_MODULE_NAME";
+ vars.SwiftOutputFileMap = "$SWIFT_OUTPUT_FILE_MAP";
+ vars.SwiftSources = "$SWIFT_SOURCES";
+
+ vars.Defines = "$DEFINES";
+ vars.Flags = "$FLAGS";
+ vars.Includes = "$INCLUDES";
+ }
+
std::string responseFlag;
- if (!useResponseFile) {
+
+ std::string cmakeVarLang = "CMAKE_";
+ cmakeVarLang += this->TargetLinkLanguage;
+
+ // build response file name
+ std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
+ const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar);
+
+ if (flag) {
+ responseFlag = flag;
+ } else if (this->TargetLinkLanguage != "CUDA") {
+ responseFlag = "@";
+ }
+
+ if (!useResponseFile || responseFlag.empty()) {
vars.Objects = "$in";
vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
} else {
- std::string cmakeVarLang = "CMAKE_";
- cmakeVarLang += this->TargetLinkLanguage;
-
- // build response file name
- std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
- const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar);
- if (flag) {
- responseFlag = flag;
- } else {
- responseFlag = "@";
- }
- rspfile = "$RSP_FILE";
- responseFlag += rspfile;
+ rule.RspFile = "$RSP_FILE";
+ responseFlag += rule.RspFile;
// build response file content
if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
- rspcontent = "$in";
+ rule.RspContent = "$in";
} else {
- rspcontent = "$in_newline";
+ rule.RspContent = "$in_newline";
+ }
+ rule.RspContent += " $LINK_PATH $LINK_LIBRARIES";
+ if (this->TargetLinkLanguage == "Swift") {
+ vars.SwiftSources = responseFlag.c_str();
+ } else {
+ vars.Objects = responseFlag.c_str();
}
- rspcontent += " $LINK_PATH $LINK_LIBRARIES";
- vars.Objects = responseFlag.c_str();
vars.LinkLibraries = "";
}
@@ -377,65 +375,51 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile)
linkCmds.insert(linkCmds.begin(), "$PRE_LINK");
linkCmds.emplace_back("$POST_BUILD");
- std::string linkCmd =
- this->GetLocalGenerator()->BuildCommandLine(linkCmds);
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(linkCmds);
// Write the linker rule with response file if needed.
- std::ostringstream comment;
- comment << "Rule for linking " << this->TargetLinkLanguage << " "
- << this->GetVisibleTypeName() << ".";
- std::ostringstream description;
- description << "Linking " << this->TargetLinkLanguage << " "
- << this->GetVisibleTypeName() << " $TARGET_FILE";
- this->GetGlobalGenerator()->AddRule(ruleName, linkCmd, description.str(),
- comment.str(),
- /*depfile*/ "",
- /*deptype*/ "", rspfile, rspcontent,
- /*restat*/ "$RESTAT",
- /*generator*/ false);
+ rule.Comment = "Rule for linking ";
+ rule.Comment += this->TargetLinkLanguage;
+ rule.Comment += " ";
+ rule.Comment += this->GetVisibleTypeName();
+ rule.Comment += ".";
+ rule.Description = "Linking ";
+ rule.Description += this->TargetLinkLanguage;
+ rule.Description += " ";
+ rule.Description += this->GetVisibleTypeName();
+ rule.Description += " $TARGET_FILE";
+ rule.Restat = "$RESTAT";
+ this->GetGlobalGenerator()->AddRule(rule);
}
- if (this->TargetNameOut != this->TargetNameReal &&
+ if (this->TargetNames.Output != this->TargetNames.Real &&
!this->GetGeneratorTarget()->IsFrameworkOnApple()) {
std::string cmakeCommand =
this->GetLocalGenerator()->ConvertToOutputFormat(
cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
if (targetType == cmStateEnums::EXECUTABLE) {
- std::vector<std::string> commandLines;
- commandLines.push_back(cmakeCommand +
- " -E cmake_symlink_executable $in $out");
- commandLines.emplace_back("$POST_BUILD");
-
- this->GetGlobalGenerator()->AddRule(
- "CMAKE_SYMLINK_EXECUTABLE",
- this->GetLocalGenerator()->BuildCommandLine(commandLines),
- "Creating executable symlink $out",
- "Rule for creating "
- "executable symlink.",
- /*depfile*/ "",
- /*deptype*/ "",
- /*rspfile*/ "",
- /*rspcontent*/ "",
- /*restat*/ "",
- /*generator*/ false);
+ cmNinjaRule rule("CMAKE_SYMLINK_EXECUTABLE");
+ {
+ std::vector<std::string> cmd;
+ cmd.push_back(cmakeCommand + " -E cmake_symlink_executable $in $out");
+ cmd.emplace_back("$POST_BUILD");
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(cmd);
+ }
+ rule.Description = "Creating executable symlink $out";
+ rule.Comment = "Rule for creating executable symlink.";
+ this->GetGlobalGenerator()->AddRule(rule);
} else {
- std::vector<std::string> commandLines;
- commandLines.push_back(cmakeCommand +
- " -E cmake_symlink_library $in $SONAME $out");
- commandLines.emplace_back("$POST_BUILD");
-
- this->GetGlobalGenerator()->AddRule(
- "CMAKE_SYMLINK_LIBRARY",
- this->GetLocalGenerator()->BuildCommandLine(commandLines),
- "Creating library symlink $out",
- "Rule for creating "
- "library symlink.",
- /*depfile*/ "",
- /*deptype*/ "",
- /*rspfile*/ "",
- /*rspcontent*/ "",
- /*restat*/ "",
- /*generator*/ false);
+ cmNinjaRule rule("CMAKE_SYMLINK_LIBRARY");
+ {
+ std::vector<std::string> cmd;
+ cmd.push_back(cmakeCommand +
+ " -E cmake_symlink_library $in $SONAME $out");
+ cmd.emplace_back("$POST_BUILD");
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(cmd);
+ }
+ rule.Description = "Creating library symlink $out";
+ rule.Comment = "Rule for creating library symlink.";
+ this->GetGlobalGenerator()->AddRule(rule);
}
}
}
@@ -565,38 +549,16 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd()
void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
{
- if (!this->GetGlobalGenerator()->GetLanguageEnabled("CUDA")) {
+ cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
+ if (!globalGen->GetLanguageEnabled("CUDA")) {
return;
}
- cmGeneratorTarget& genTarget = *this->GetGeneratorTarget();
-
- // determine if we need to do any device linking for this target
- const std::string cuda_lang("CUDA");
- cmGeneratorTarget::LinkClosure const* closure =
- genTarget.GetLinkClosure(this->GetConfigName());
-
- const bool hasCUDA =
- (std::find(closure->Languages.begin(), closure->Languages.end(),
- cuda_lang) != closure->Languages.end());
-
- bool doDeviceLinking = false;
- if (const char* resolveDeviceSymbols =
- genTarget.GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
- doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
- } else {
- switch (genTarget.GetType()) {
- case cmStateEnums::SHARED_LIBRARY:
- case cmStateEnums::MODULE_LIBRARY:
- case cmStateEnums::EXECUTABLE:
- doDeviceLinking = true;
- break;
- default:
- break;
- }
- }
+ cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
- if (!(doDeviceLinking && hasCUDA)) {
+ bool requiresDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->GetLocalGenerator(), this->ConfigName);
+ if (!requiresDeviceLinking) {
return;
}
@@ -605,44 +567,44 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
// First and very important step is to make sure while inside this
// step our link language is set to CUDA
std::string cudaLinkLanguage = "CUDA";
- std::string const objExt =
+ std::string const& objExt =
this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION");
std::string const cfgName = this->GetConfigName();
std::string const targetOutputReal = ConvertToNinjaPath(
- genTarget.ObjectDirectory + "cmake_device_link" + objExt);
+ genTarget->ObjectDirectory + "cmake_device_link" + objExt);
std::string const targetOutputImplib = ConvertToNinjaPath(
- genTarget.GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact));
+ genTarget->GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact));
this->DeviceLinkObject = targetOutputReal;
// Write comments.
cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
- const cmStateEnums::TargetType targetType = genTarget.GetType();
+ const cmStateEnums::TargetType targetType = genTarget->GetType();
this->GetBuildFileStream() << "# Device Link build statements for "
<< cmState::GetTargetTypeName(targetType)
<< " target " << this->GetTargetName() << "\n\n";
// Compute the comment.
- std::ostringstream comment;
- comment << "Link the " << this->GetVisibleTypeName() << " "
- << targetOutputReal;
+ cmNinjaBuild build(this->LanguageLinkerDeviceRule());
+ build.Comment = "Link the ";
+ build.Comment += this->GetVisibleTypeName();
+ build.Comment += " ";
+ build.Comment += targetOutputReal;
- cmNinjaDeps emptyDeps;
- cmNinjaVars vars;
+ cmNinjaVars& vars = build.Variables;
// Compute outputs.
- cmNinjaDeps outputs;
- outputs.push_back(targetOutputReal);
+ build.Outputs.push_back(targetOutputReal);
// Compute specific libraries to link with.
- cmNinjaDeps explicitDeps = this->GetObjects();
- cmNinjaDeps implicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage);
+ build.ExplicitDeps = this->GetObjects();
+ build.ImplicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage);
std::string frameworkPath;
std::string linkPath;
- std::string createRule = genTarget.GetCreateRuleVariable(
+ std::string createRule = genTarget->GetCreateRuleVariable(
this->TargetLinkLanguage, this->GetConfigName());
const bool useWatcomQuote =
this->GetMakefile()->IsOn(createRule + "_USE_WATCOM_QUOTE");
@@ -655,14 +617,14 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
new cmNinjaLinkLineDeviceComputer(
this->GetLocalGenerator(),
this->GetLocalGenerator()->GetStateSnapshot().GetDirectory(),
- this->GetGlobalGenerator()));
+ globalGen));
linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
localGen.GetTargetFlags(
linkLineComputer.get(), this->GetConfigName(), vars["LINK_LIBRARIES"],
- vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, &genTarget);
+ vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, genTarget);
- this->addPoolNinjaVariable("JOB_POOL_LINK", &genTarget, vars);
+ this->addPoolNinjaVariable("JOB_POOL_LINK", genTarget, vars);
vars["LINK_FLAGS"] =
cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]);
@@ -676,21 +638,21 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
// code between the Makefile executable and library generators.
if (targetType == cmStateEnums::EXECUTABLE) {
std::string t = vars["FLAGS"];
- localGen.AddArchitectureFlags(t, &genTarget, cudaLinkLanguage, cfgName);
+ localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, cfgName);
vars["FLAGS"] = t;
} else {
std::string t = vars["ARCH_FLAGS"];
- localGen.AddArchitectureFlags(t, &genTarget, cudaLinkLanguage, cfgName);
+ localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, cfgName);
vars["ARCH_FLAGS"] = t;
t.clear();
- localGen.AddLanguageFlagsForLinking(t, &genTarget, cudaLinkLanguage,
+ localGen.AddLanguageFlagsForLinking(t, genTarget, cudaLinkLanguage,
cfgName);
vars["LANGUAGE_COMPILE_FLAGS"] = t;
}
- if (this->GetGeneratorTarget()->HasSOName(cfgName)) {
+ if (genTarget->HasSOName(cfgName)) {
vars["SONAME_FLAG"] =
this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage);
- vars["SONAME"] = this->TargetNameSO;
+ vars["SONAME"] = this->TargetNames.SharedObject;
if (targetType == cmStateEnums::SHARED_LIBRARY) {
std::string install_dir =
this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName);
@@ -701,7 +663,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
}
}
- if (!this->TargetNameImport.empty()) {
+ if (!this->TargetNames.ImportLibrary.empty()) {
const std::string impLibPath = localGen.ConvertToOutputFormat(
targetOutputImplib, cmOutputConverter::SHELL);
vars["TARGET_IMPLIB"] = impLibPath;
@@ -715,7 +677,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
this->SetMsvcTargetPdbVariable(vars);
- if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
+ if (globalGen->IsGCCOnWindows()) {
// ar.exe can't handle backslashes in rsp files (implicitly used by gcc)
std::string& linkLibraries = vars["LINK_LIBRARIES"];
std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/');
@@ -723,102 +685,173 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
std::replace(link_path.begin(), link_path.end(), '\\', '/');
}
- cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator();
-
// Device linking currently doesn't support response files so
// do not check if the user has explicitly forced a response file.
int const commandLineLengthLimit =
static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
- globalGen.GetRuleCmdLength(this->LanguageLinkerDeviceRule());
+ globalGen->GetRuleCmdLength(this->LanguageLinkerDeviceRule());
- const std::string rspfile = this->ConvertToNinjaPath(
- std::string("CMakeFiles/") + genTarget.GetName() + ".rsp");
+ build.RspFile = this->ConvertToNinjaPath(std::string("CMakeFiles/") +
+ genTarget->GetName() + ".rsp");
// Gather order-only dependencies.
- cmNinjaDeps orderOnlyDeps;
this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(),
- orderOnlyDeps);
+ build.OrderOnlyDeps);
// Write the build statement for this target.
bool usedResponseFile = false;
- globalGen.WriteBuild(this->GetBuildFileStream(), comment.str(),
- this->LanguageLinkerDeviceRule(), outputs,
- /*implicitOuts=*/cmNinjaDeps(), explicitDeps,
- implicitDeps, orderOnlyDeps, vars, rspfile,
- commandLineLengthLimit, &usedResponseFile);
- this->WriteDeviceLinkRule(false);
+ globalGen->WriteBuild(this->GetBuildFileStream(), build,
+ commandLineLengthLimit, &usedResponseFile);
+ this->WriteDeviceLinkRule(usedResponseFile);
}
void cmNinjaNormalTargetGenerator::WriteLinkStatement()
{
- cmGeneratorTarget& gt = *this->GetGeneratorTarget();
+ cmMakefile* mf = this->GetMakefile();
+ cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
+ cmGeneratorTarget* gt = this->GetGeneratorTarget();
+
const std::string cfgName = this->GetConfigName();
- std::string targetOutput = ConvertToNinjaPath(gt.GetFullPath(cfgName));
+ std::string targetOutput = ConvertToNinjaPath(gt->GetFullPath(cfgName));
std::string targetOutputReal = ConvertToNinjaPath(
- gt.GetFullPath(cfgName, cmStateEnums::RuntimeBinaryArtifact,
- /*realname=*/true));
+ gt->GetFullPath(cfgName, cmStateEnums::RuntimeBinaryArtifact,
+ /*realname=*/true));
std::string targetOutputImplib = ConvertToNinjaPath(
- gt.GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact));
+ gt->GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact));
- if (gt.IsAppBundleOnApple()) {
+ if (gt->IsAppBundleOnApple()) {
// Create the app bundle
- std::string outpath = gt.GetDirectory(cfgName);
- this->OSXBundleGenerator->CreateAppBundle(this->TargetNameOut, outpath);
+ std::string outpath = gt->GetDirectory(cfgName);
+ this->OSXBundleGenerator->CreateAppBundle(this->TargetNames.Output,
+ outpath);
// Calculate the output path
targetOutput = outpath;
targetOutput += "/";
- targetOutput += this->TargetNameOut;
+ targetOutput += this->TargetNames.Output;
targetOutput = this->ConvertToNinjaPath(targetOutput);
targetOutputReal = outpath;
targetOutputReal += "/";
- targetOutputReal += this->TargetNameReal;
+ targetOutputReal += this->TargetNames.Real;
targetOutputReal = this->ConvertToNinjaPath(targetOutputReal);
- } else if (gt.IsFrameworkOnApple()) {
+ } else if (gt->IsFrameworkOnApple()) {
// Create the library framework.
- this->OSXBundleGenerator->CreateFramework(this->TargetNameOut,
- gt.GetDirectory(cfgName));
- } else if (gt.IsCFBundleOnApple()) {
+ this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output,
+ gt->GetDirectory(cfgName));
+ } else if (gt->IsCFBundleOnApple()) {
// Create the core foundation bundle.
- this->OSXBundleGenerator->CreateCFBundle(this->TargetNameOut,
- gt.GetDirectory(cfgName));
+ this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output,
+ gt->GetDirectory(cfgName));
}
// Write comments.
cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
- const cmStateEnums::TargetType targetType = gt.GetType();
+ const cmStateEnums::TargetType targetType = gt->GetType();
this->GetBuildFileStream()
<< "# Link build statements for " << cmState::GetTargetTypeName(targetType)
<< " target " << this->GetTargetName() << "\n\n";
- cmNinjaDeps emptyDeps;
- cmNinjaVars vars;
+ cmNinjaBuild linkBuild(this->LanguageLinkerRule());
+ cmNinjaVars& vars = linkBuild.Variables;
// Compute the comment.
- std::ostringstream comment;
- comment << "Link the " << this->GetVisibleTypeName() << " "
- << targetOutputReal;
+ linkBuild.Comment = "Link the ";
+ linkBuild.Comment += this->GetVisibleTypeName();
+ linkBuild.Comment += " ";
+ linkBuild.Comment += targetOutputReal;
// Compute outputs.
- cmNinjaDeps outputs;
- outputs.push_back(targetOutputReal);
+ linkBuild.Outputs.push_back(targetOutputReal);
+
+ if (this->TargetLinkLanguage == "Swift") {
+ vars["SWIFT_LIBRARY_NAME"] = [this]() -> std::string {
+ cmGeneratorTarget::Names targetNames =
+ this->GetGeneratorTarget()->GetLibraryNames(this->GetConfigName());
+ return targetNames.Base;
+ }();
+
+ vars["SWIFT_MODULE_NAME"] = [gt]() -> std::string {
+ if (const char* name = gt->GetProperty("Swift_MODULE_NAME")) {
+ return name;
+ }
+ return gt->GetName();
+ }();
+
+ vars["SWIFT_MODULE"] = [this](const std::string& module) -> std::string {
+ std::string directory =
+ this->GetLocalGenerator()->GetCurrentBinaryDirectory();
+ if (const char* prop = this->GetGeneratorTarget()->GetProperty(
+ "Swift_MODULE_DIRECTORY")) {
+ directory = prop;
+ }
+
+ std::string name = module + ".swiftmodule";
+ if (const char* prop =
+ this->GetGeneratorTarget()->GetProperty("Swift_MODULE")) {
+ name = prop;
+ }
+
+ return this->GetLocalGenerator()->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(directory + "/" + name),
+ cmOutputConverter::SHELL);
+ }(vars["SWIFT_MODULE_NAME"]);
+
+ vars["SWIFT_OUTPUT_FILE_MAP"] =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(gt->GetSupportDirectory() +
+ "/output-file-map.json"),
+ cmOutputConverter::SHELL);
+
+ vars["SWIFT_SOURCES"] = [this]() -> std::string {
+ std::vector<cmSourceFile const*> sources;
+ std::stringstream oss;
+
+ this->GetGeneratorTarget()->GetObjectSources(sources,
+ this->GetConfigName());
+ cmLocalGenerator const* LocalGen = this->GetLocalGenerator();
+ for (const auto& source : sources) {
+ oss << " "
+ << LocalGen->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(this->GetSourceFilePath(source)),
+ cmOutputConverter::SHELL);
+ }
+ return oss.str();
+ }();
+
+ // Since we do not perform object builds, compute the
+ // defines/flags/includes here so that they can be passed along
+ // appropriately.
+ vars["DEFINES"] = this->GetDefines("Swift");
+ vars["FLAGS"] = this->GetFlags("Swift");
+ vars["INCLUDES"] = this->GetIncludes("Swift");
+ }
// Compute specific libraries to link with.
- cmNinjaDeps explicitDeps = this->GetObjects();
- cmNinjaDeps implicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage);
+ if (this->TargetLinkLanguage == "Swift") {
+ std::vector<cmSourceFile const*> sources;
+ gt->GetObjectSources(sources, this->GetConfigName());
+ for (const auto& source : sources) {
+ linkBuild.Outputs.push_back(
+ this->ConvertToNinjaPath(this->GetObjectFilePath(source)));
+ linkBuild.ExplicitDeps.push_back(
+ this->ConvertToNinjaPath(this->GetSourceFilePath(source)));
+ }
- if (!this->DeviceLinkObject.empty()) {
- explicitDeps.push_back(this->DeviceLinkObject);
+ linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]);
+ } else {
+ linkBuild.ExplicitDeps = this->GetObjects();
}
+ linkBuild.ImplicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage);
- cmMakefile* mf = this->GetMakefile();
+ if (!this->DeviceLinkObject.empty()) {
+ linkBuild.ExplicitDeps.push_back(this->DeviceLinkObject);
+ }
std::string frameworkPath;
std::string linkPath;
- cmGeneratorTarget& genTarget = *this->GetGeneratorTarget();
- std::string createRule = genTarget.GetCreateRuleVariable(
- this->TargetLinkLanguage, this->GetConfigName());
+ std::string createRule =
+ gt->GetCreateRuleVariable(this->TargetLinkLanguage, this->GetConfigName());
bool useWatcomQuote = mf->IsOn(createRule + "_USE_WATCOM_QUOTE");
cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
@@ -826,14 +859,14 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
localGen.ConvertToOutputFormat(targetOutputReal, cmOutputConverter::SHELL);
std::unique_ptr<cmLinkLineComputer> linkLineComputer(
- this->GetGlobalGenerator()->CreateLinkLineComputer(
+ globalGen->CreateLinkLineComputer(
this->GetLocalGenerator(),
this->GetLocalGenerator()->GetStateSnapshot().GetDirectory()));
linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
- localGen.GetTargetFlags(
- linkLineComputer.get(), this->GetConfigName(), vars["LINK_LIBRARIES"],
- vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, &genTarget);
+ localGen.GetTargetFlags(linkLineComputer.get(), this->GetConfigName(),
+ vars["LINK_LIBRARIES"], vars["FLAGS"],
+ vars["LINK_FLAGS"], frameworkPath, linkPath, gt);
// Add OS X version flags, if any.
if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
@@ -844,7 +877,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
"CURRENT", false);
}
- this->addPoolNinjaVariable("JOB_POOL_LINK", &gt, vars);
+ this->addPoolNinjaVariable("JOB_POOL_LINK", gt, vars);
this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"]);
vars["LINK_FLAGS"] =
@@ -854,7 +887,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
vars["LINK_PATH"] = frameworkPath + linkPath;
std::string lwyuFlags;
- if (genTarget.GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
+ if (gt->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
lwyuFlags = " -Wl,--no-as-needed";
}
@@ -863,25 +896,23 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
// code between the Makefile executable and library generators.
if (targetType == cmStateEnums::EXECUTABLE) {
std::string t = vars["FLAGS"];
- localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName);
+ localGen.AddArchitectureFlags(t, gt, TargetLinkLanguage, cfgName);
t += lwyuFlags;
vars["FLAGS"] = t;
} else {
std::string t = vars["ARCH_FLAGS"];
- localGen.AddArchitectureFlags(t, &genTarget, TargetLinkLanguage, cfgName);
+ localGen.AddArchitectureFlags(t, gt, TargetLinkLanguage, cfgName);
vars["ARCH_FLAGS"] = t;
t.clear();
t += lwyuFlags;
- localGen.AddLanguageFlagsForLinking(t, &genTarget, TargetLinkLanguage,
- cfgName);
+ localGen.AddLanguageFlagsForLinking(t, gt, TargetLinkLanguage, cfgName);
vars["LANGUAGE_COMPILE_FLAGS"] = t;
}
- if (this->GetGeneratorTarget()->HasSOName(cfgName)) {
+ if (gt->HasSOName(cfgName)) {
vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage);
- vars["SONAME"] = this->TargetNameSO;
+ vars["SONAME"] = this->TargetNames.SharedObject;
if (targetType == cmStateEnums::SHARED_LIBRARY) {
- std::string install_dir =
- this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName);
+ std::string install_dir = gt->GetInstallNameDirForBuildTree(cfgName);
if (!install_dir.empty()) {
vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat(
install_dir, cmOutputConverter::SHELL);
@@ -891,12 +922,12 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
cmNinjaDeps byproducts;
- if (!this->TargetNameImport.empty()) {
+ if (!this->TargetNames.ImportLibrary.empty()) {
const std::string impLibPath = localGen.ConvertToOutputFormat(
targetOutputImplib, cmOutputConverter::SHELL);
vars["TARGET_IMPLIB"] = impLibPath;
EnsureParentDirectoryExists(impLibPath);
- if (genTarget.HasImportLibrary(cfgName)) {
+ if (gt->HasImportLibrary(cfgName)) {
byproducts.push_back(targetOutputImplib);
}
}
@@ -907,7 +938,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
std::string prefix;
std::string base;
std::string suffix;
- this->GetGeneratorTarget()->GetFullNameComponents(prefix, base, suffix);
+ gt->GetFullNameComponents(prefix, base, suffix);
std::string dbg_suffix = ".dbg";
// TODO: Where to document?
if (mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) {
@@ -916,12 +947,12 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
vars["TARGET_PDB"] = base + suffix + dbg_suffix;
}
- const std::string objPath = GetGeneratorTarget()->GetSupportDirectory();
+ const std::string objPath = gt->GetSupportDirectory();
vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
EnsureDirectoryExists(objPath);
- if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
+ if (globalGen->IsGCCOnWindows()) {
// ar.exe can't handle backslashes in rsp files (implicitly used by gcc)
std::string& linkLibraries = vars["LINK_LIBRARIES"];
std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/');
@@ -930,8 +961,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
}
const std::vector<cmCustomCommand>* cmdLists[3] = {
- &gt.GetPreBuildCommands(), &gt.GetPreLinkCommands(),
- &gt.GetPostBuildCommands()
+ &gt->GetPreBuildCommands(), &gt->GetPreLinkCommands(),
+ &gt->GetPostBuildCommands()
};
std::vector<std::string> preLinkCmdLines, postBuildCmdLines;
@@ -951,7 +982,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
// maybe create .def file from list of objects
cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
- gt.GetModuleDefinitionInfo(this->GetConfigName());
+ gt->GetModuleDefinitionInfo(this->GetConfigName());
if (mdi && mdi->DefFileGenerated) {
std::string cmakeCommand =
this->GetLocalGenerator()->ConvertToOutputFormat(
@@ -983,8 +1014,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
}
}
// If we have any PRE_LINK commands, we need to go back to CMAKE_BINARY_DIR
- // for
- // the link commands.
+ // for the link commands.
if (!preLinkCmdLines.empty()) {
const std::string homeOutDir = localGen.ConvertToOutputFormat(
localGen.GetBinaryDirectory(), cmOutputConverter::SHELL);
@@ -998,92 +1028,99 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
cmNinjaVars symlinkVars;
bool const symlinkNeeded =
- (targetOutput != targetOutputReal && !gt.IsFrameworkOnApple());
+ (targetOutput != targetOutputReal && !gt->IsFrameworkOnApple());
if (!symlinkNeeded) {
vars["POST_BUILD"] = postBuildCmdLine;
} else {
vars["POST_BUILD"] = cmGlobalNinjaGenerator::SHELL_NOOP;
symlinkVars["POST_BUILD"] = postBuildCmdLine;
}
- cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator();
+
+ std::string cmakeVarLang = "CMAKE_";
+ cmakeVarLang += this->TargetLinkLanguage;
+
+ // build response file name
+ std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
+
+ const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar);
bool const lang_supports_response =
- !(this->TargetLinkLanguage == "RC" || this->TargetLinkLanguage == "CUDA");
+ !(this->TargetLinkLanguage == "RC" ||
+ (this->TargetLinkLanguage == "CUDA" && !flag));
int commandLineLengthLimit = -1;
if (!lang_supports_response || !this->ForceResponseFile()) {
commandLineLengthLimit =
static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
- globalGen.GetRuleCmdLength(this->LanguageLinkerRule());
+ globalGen->GetRuleCmdLength(linkBuild.Rule);
}
- const std::string rspfile = this->ConvertToNinjaPath(
- std::string("CMakeFiles/") + gt.GetName() + ".rsp");
+ linkBuild.RspFile = this->ConvertToNinjaPath(std::string("CMakeFiles/") +
+ gt->GetName() + ".rsp");
// Gather order-only dependencies.
- cmNinjaDeps orderOnlyDeps;
- this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(),
- orderOnlyDeps);
+ this->GetLocalGenerator()->AppendTargetDepends(gt, linkBuild.OrderOnlyDeps);
// Ninja should restat after linking if and only if there are byproducts.
vars["RESTAT"] = byproducts.empty() ? "" : "1";
for (std::string const& o : byproducts) {
- this->GetGlobalGenerator()->SeenCustomCommandOutput(o);
- outputs.push_back(o);
+ globalGen->SeenCustomCommandOutput(o);
+ linkBuild.Outputs.push_back(o);
}
// Write the build statement for this target.
bool usedResponseFile = false;
- globalGen.WriteBuild(this->GetBuildFileStream(), comment.str(),
- this->LanguageLinkerRule(), outputs,
- /*implicitOuts=*/cmNinjaDeps(), explicitDeps,
- implicitDeps, orderOnlyDeps, vars, rspfile,
- commandLineLengthLimit, &usedResponseFile);
+ globalGen->WriteBuild(this->GetBuildFileStream(), linkBuild,
+ commandLineLengthLimit, &usedResponseFile);
this->WriteLinkRule(usedResponseFile);
if (symlinkNeeded) {
if (targetType == cmStateEnums::EXECUTABLE) {
- globalGen.WriteBuild(
- this->GetBuildFileStream(),
- "Create executable symlink " + targetOutput,
- "CMAKE_SYMLINK_EXECUTABLE", cmNinjaDeps(1, targetOutput),
- /*implicitOuts=*/cmNinjaDeps(), cmNinjaDeps(1, targetOutputReal),
- emptyDeps, emptyDeps, symlinkVars);
+ cmNinjaBuild build("CMAKE_SYMLINK_EXECUTABLE");
+ build.Comment = "Create executable symlink " + targetOutput;
+ build.Outputs.push_back(targetOutput);
+ build.ExplicitDeps.push_back(targetOutputReal);
+ build.Variables = std::move(symlinkVars);
+ globalGen->WriteBuild(this->GetBuildFileStream(), build);
} else {
- cmNinjaDeps symlinks;
- std::string const soName =
- this->ConvertToNinjaPath(this->GetTargetFilePath(this->TargetNameSO));
+ cmNinjaBuild build("CMAKE_SYMLINK_LIBRARY");
+ build.Comment = "Create library symlink " + targetOutput;
+
+ std::string const soName = this->ConvertToNinjaPath(
+ this->GetTargetFilePath(this->TargetNames.SharedObject));
// If one link has to be created.
if (targetOutputReal == soName || targetOutput == soName) {
- symlinkVars["SONAME"] = soName;
+ symlinkVars["SONAME"] =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ soName, cmOutputConverter::SHELL);
} else {
symlinkVars["SONAME"].clear();
- symlinks.push_back(soName);
+ build.Outputs.push_back(soName);
}
- symlinks.push_back(targetOutput);
- globalGen.WriteBuild(
- this->GetBuildFileStream(), "Create library symlink " + targetOutput,
- "CMAKE_SYMLINK_LIBRARY", symlinks,
- /*implicitOuts=*/cmNinjaDeps(), cmNinjaDeps(1, targetOutputReal),
- emptyDeps, emptyDeps, symlinkVars);
+ build.Outputs.push_back(targetOutput);
+ build.ExplicitDeps.push_back(targetOutputReal);
+ build.Variables = std::move(symlinkVars);
+
+ globalGen->WriteBuild(this->GetBuildFileStream(), build);
}
}
// Add aliases for the file name and the target name.
- globalGen.AddTargetAlias(this->TargetNameOut, &gt);
- globalGen.AddTargetAlias(this->GetTargetName(), &gt);
+ globalGen->AddTargetAlias(this->TargetNames.Output, gt);
+ globalGen->AddTargetAlias(this->GetTargetName(), gt);
}
void cmNinjaNormalTargetGenerator::WriteObjectLibStatement()
{
// Write a phony output that depends on all object files.
- cmNinjaDeps outputs;
- this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
- outputs);
- cmNinjaDeps depends = this->GetObjects();
- this->GetGlobalGenerator()->WritePhonyBuild(
- this->GetBuildFileStream(), "Object library " + this->GetTargetName(),
- outputs, depends);
+ {
+ cmNinjaBuild build("phony");
+ build.Comment = "Object library " + this->GetTargetName();
+ this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
+ build.Outputs);
+ build.ExplicitDeps = this->GetObjects();
+ this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build);
+ }
// Add aliases for the target name.
this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h
index 01cc8816e..14991a286 100644
--- a/Source/cmNinjaNormalTargetGenerator.h
+++ b/Source/cmNinjaNormalTargetGenerator.h
@@ -5,13 +5,12 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cmGeneratorTarget.h"
#include "cmNinjaTargetGenerator.h"
#include <string>
#include <vector>
-class cmGeneratorTarget;
-
class cmNinjaNormalTargetGenerator : public cmNinjaTargetGenerator
{
public:
@@ -40,11 +39,7 @@ private:
private:
// Target name info.
- std::string TargetNameOut;
- std::string TargetNameSO;
- std::string TargetNameReal;
- std::string TargetNameImport;
- std::string TargetNamePDB;
+ cmGeneratorTarget::Names TargetNames;
std::string TargetLinkLanguage;
std::string DeviceLinkObject;
};
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 82bc5f204..2139a452d 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -9,7 +9,7 @@
#include <iterator>
#include <map>
#include <memory> // IWYU pragma: keep
-#include <sstream>
+#include <ostream>
#include <utility>
#include "cmAlgorithms.h"
@@ -19,13 +19,13 @@
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalNinjaGenerator.h"
-#include "cmListFileCache.h" // for BT
#include "cmLocalGenerator.h"
#include "cmLocalNinjaGenerator.h"
#include "cmMakefile.h"
#include "cmNinjaNormalTargetGenerator.h"
#include "cmNinjaUtilityTargetGenerator.h"
#include "cmOutputConverter.h"
+#include "cmRange.h"
#include "cmRulePlaceholderExpander.h"
#include "cmSourceFile.h"
#include "cmState.h"
@@ -33,7 +33,8 @@
#include "cmSystemTools.h"
#include "cmake.h"
-cmNinjaTargetGenerator* cmNinjaTargetGenerator::New(cmGeneratorTarget* target)
+std::unique_ptr<cmNinjaTargetGenerator> cmNinjaTargetGenerator::New(
+ cmGeneratorTarget* target)
{
switch (target->GetType()) {
case cmStateEnums::EXECUTABLE:
@@ -41,14 +42,14 @@ cmNinjaTargetGenerator* cmNinjaTargetGenerator::New(cmGeneratorTarget* target)
case cmStateEnums::STATIC_LIBRARY:
case cmStateEnums::MODULE_LIBRARY:
case cmStateEnums::OBJECT_LIBRARY:
- return new cmNinjaNormalTargetGenerator(target);
+ return cm::make_unique<cmNinjaNormalTargetGenerator>(target);
case cmStateEnums::UTILITY:
case cmStateEnums::GLOBAL_TARGET:
- return new cmNinjaUtilityTargetGenerator(target);
+ return cm::make_unique<cmNinjaUtilityTargetGenerator>(target);
default:
- return nullptr;
+ return std::unique_ptr<cmNinjaTargetGenerator>();
}
}
@@ -59,13 +60,10 @@ cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmGeneratorTarget* target)
, LocalGenerator(
static_cast<cmLocalNinjaGenerator*>(target->GetLocalGenerator()))
{
- MacOSXContentGenerator = new MacOSXContentGeneratorType(this);
+ MacOSXContentGenerator = cm::make_unique<MacOSXContentGeneratorType>(this);
}
-cmNinjaTargetGenerator::~cmNinjaTargetGenerator()
-{
- delete this->MacOSXContentGenerator;
-}
+cmNinjaTargetGenerator::~cmNinjaTargetGenerator() = default;
cmGeneratedFileStream& cmNinjaTargetGenerator::GetBuildFileStream() const
{
@@ -102,6 +100,12 @@ bool cmNinjaTargetGenerator::NeedExplicitPreprocessing(
return lang == "Fortran";
}
+bool cmNinjaTargetGenerator::UsePreprocessedSource(
+ std::string const& lang) const
+{
+ return lang == "Fortran";
+}
+
std::string cmNinjaTargetGenerator::LanguageDyndepRule(
const std::string& lang) const
{
@@ -451,10 +455,6 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
vars.TargetCompilePDB = "$TARGET_COMPILE_PDB";
vars.ObjectDir = "$OBJECT_DIR";
vars.ObjectFileDir = "$OBJECT_FILE_DIR";
- if (lang == "Swift") {
- vars.SwiftAuxiliarySources = "$SWIFT_AUXILIARY_SOURCES";
- vars.SwiftModuleName = "$SWIFT_MODULE_NAME";
- }
// For some cases we do an explicit preprocessor invocation.
bool const explicitPP = this->NeedExplicitPreprocessing(lang);
@@ -465,12 +465,12 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
std::string flags = "$FLAGS";
std::string responseFlag;
- bool const lang_supports_response = !(lang == "RC" || lang == "CUDA");
+ bool const lang_supports_response = lang != "RC";
if (lang_supports_response && this->ForceResponseFile()) {
std::string const responseFlagVar =
"CMAKE_" + lang + "_RESPONSE_FILE_FLAG";
responseFlag = this->Makefile->GetSafeDefinition(responseFlagVar);
- if (responseFlag.empty()) {
+ if (responseFlag.empty() && lang != "CUDA") {
responseFlag = "@";
}
}
@@ -490,15 +490,15 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
launcher += " ";
}
- if (explicitPP) {
- // Lookup the explicit preprocessing rule.
- std::string const ppVar = "CMAKE_" + lang + "_PREPROCESS_SOURCE";
- std::string const ppCmd =
- this->GetMakefile()->GetRequiredDefinition(ppVar);
+ std::string const cmakeCmd =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
+ if (explicitPP) {
+ cmNinjaRule rule(this->LanguagePreprocessRule(lang));
// Explicit preprocessing always uses a depfile.
- std::string const ppDeptype; // no deps= for multiple outputs
- std::string const ppDepfile = "$DEP_FILE";
+ rule.DepType = ""; // no deps= for multiple outputs
+ rule.DepFile = "$DEP_FILE";
cmRulePlaceholderExpander::RuleVariables ppVars;
ppVars.CMTargetName = vars.CMTargetName;
@@ -506,7 +506,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
ppVars.Language = vars.Language;
ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
ppVars.PreprocessedSource = "$out";
- ppVars.DependencyFile = ppDepfile.c_str();
+ ppVars.DependencyFile = rule.DepFile.c_str();
// Preprocessing uses the original source,
// compilation uses preprocessed output.
@@ -525,13 +525,15 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
ppVars.Includes = vars.Includes;
// If using a response file, move defines, includes, and flags into it.
- std::string ppRspFile;
- std::string ppRspContent;
if (!responseFlag.empty()) {
- ppRspFile = "$RSP_FILE";
- ppRspContent = std::string(" ") + ppVars.Defines + " " +
- ppVars.Includes + " " + ppFlags;
- ppFlags = responseFlag + ppRspFile;
+ rule.RspFile = "$RSP_FILE";
+ rule.RspContent = " ";
+ rule.RspContent += ppVars.Defines;
+ rule.RspContent += " ";
+ rule.RspContent += ppVars.Includes;
+ rule.RspContent += " ";
+ rule.RspContent += ppFlags;
+ ppFlags = responseFlag + rule.RspFile;
ppVars.Defines = "";
ppVars.Includes = "";
}
@@ -540,7 +542,13 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
// Rule for preprocessing source file.
std::vector<std::string> ppCmds;
- cmSystemTools::ExpandListArgument(ppCmd, ppCmds);
+ {
+ // Lookup the explicit preprocessing rule.
+ std::string ppVar = "CMAKE_" + lang;
+ ppVar += "_PREPROCESS_SOURCE";
+ cmSystemTools::ExpandListArgument(
+ this->GetMakefile()->GetRequiredDefinition(ppVar), ppCmds);
+ }
for (std::string& i : ppCmds) {
i = launcher + i;
@@ -549,96 +557,93 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
}
// Run CMake dependency scanner on preprocessed output.
- std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
- cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
- ppCmds.push_back(
- cmake +
- " -E cmake_ninja_depends"
- " --tdi=" +
- tdi +
- " --pp=$out"
- " --dep=$DEP_FILE" +
- (needDyndep ? " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE" : ""));
-
- std::string const ppCmdLine =
- this->GetLocalGenerator()->BuildCommandLine(ppCmds);
+ {
+ std::string ccmd = cmakeCmd;
+ ccmd += " -E cmake_ninja_depends --tdi=";
+ ccmd += tdi;
+ ccmd += " --lang=";
+ ccmd += lang;
+ ccmd += " --pp=$out --dep=$DEP_FILE";
+ if (needDyndep) {
+ ccmd += " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE";
+ }
+ ppCmds.emplace_back(std::move(ccmd));
+ }
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(ppCmds);
// Write the rule for preprocessing file of the given language.
- std::ostringstream ppComment;
- ppComment << "Rule for preprocessing " << lang << " files.";
- std::ostringstream ppDesc;
- ppDesc << "Building " << lang << " preprocessed $out";
- this->GetGlobalGenerator()->AddRule(
- this->LanguagePreprocessRule(lang), ppCmdLine, ppDesc.str(),
- ppComment.str(), ppDepfile, ppDeptype, ppRspFile, ppRspContent,
- /*restat*/ "",
- /*generator*/ false);
+ rule.Comment = "Rule for preprocessing ";
+ rule.Comment += lang;
+ rule.Comment += " files.";
+ rule.Description = "Building ";
+ rule.Description += lang;
+ rule.Description += " preprocessed $out";
+ this->GetGlobalGenerator()->AddRule(rule);
}
if (needDyndep) {
// Write the rule for ninja dyndep file generation.
- std::vector<std::string> ddCmds;
-
+ cmNinjaRule rule(this->LanguageDyndepRule(lang));
// Command line length is almost always limited -> use response file for
// dyndep rules
- std::string ddRspFile = "$out.rsp";
- std::string ddRspContent = "$in";
- std::string ddInput = "@" + ddRspFile;
-
- // Run CMake dependency scanner on preprocessed output.
- std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
- cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
- ddCmds.push_back(cmake +
- " -E cmake_ninja_dyndep"
- " --tdi=" +
- tdi +
- " --dd=$out"
- " " +
- ddInput);
-
- std::string const ddCmdLine =
- this->GetLocalGenerator()->BuildCommandLine(ddCmds);
-
- std::ostringstream ddComment;
- ddComment << "Rule to generate ninja dyndep files for " << lang << ".";
- std::ostringstream ddDesc;
- ddDesc << "Generating " << lang << " dyndep file $out";
- this->GetGlobalGenerator()->AddRule(
- this->LanguageDyndepRule(lang), ddCmdLine, ddDesc.str(), ddComment.str(),
- /*depfile*/ "",
- /*deps*/ "", ddRspFile, ddRspContent,
- /*restat*/ "",
- /*generator*/ false);
+ rule.RspFile = "$out.rsp";
+ rule.RspContent = "$in";
+
+ // Run CMake dependency scanner on the source file (using the preprocessed
+ // source if that was performed).
+ {
+ std::vector<std::string> ddCmds;
+ {
+ std::string ccmd = cmakeCmd;
+ ccmd += " -E cmake_ninja_dyndep --tdi=";
+ ccmd += tdi;
+ ccmd += " --lang=";
+ ccmd += lang;
+ ccmd += " --dd=$out ";
+ ccmd += "@";
+ ccmd += rule.RspFile;
+ ddCmds.emplace_back(std::move(ccmd));
+ }
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(ddCmds);
+ }
+ rule.Comment = "Rule to generate ninja dyndep files for ";
+ rule.Comment += lang;
+ rule.Comment += ".";
+ rule.Description = "Generating ";
+ rule.Description += lang;
+ rule.Description += " dyndep file $out";
+ this->GetGlobalGenerator()->AddRule(rule);
}
+ cmNinjaRule rule(this->LanguageCompilerRule(lang));
// If using a response file, move defines, includes, and flags into it.
- std::string rspfile;
- std::string rspcontent;
if (!responseFlag.empty()) {
- rspfile = "$RSP_FILE";
- rspcontent =
- std::string(" ") + vars.Defines + " " + vars.Includes + " " + flags;
- flags = responseFlag + rspfile;
+ rule.RspFile = "$RSP_FILE";
+ rule.RspContent = " ";
+ rule.RspContent += vars.Defines;
+ rule.RspContent += " ";
+ rule.RspContent += vars.Includes;
+ rule.RspContent += " ";
+ rule.RspContent += flags;
+ flags = responseFlag + rule.RspFile;
vars.Defines = "";
vars.Includes = "";
}
// Tell ninja dependency format so all deps can be loaded into a database
- std::string deptype;
- std::string depfile;
std::string cldeps;
if (explicitPP) {
// The explicit preprocessing step will handle dependency scanning.
} else if (this->NeedDepTypeMSVC(lang)) {
- deptype = "msvc";
- depfile.clear();
+ rule.DepType = "msvc";
+ rule.DepFile.clear();
flags += " /showIncludes";
} else if (mf->IsOn("CMAKE_NINJA_CMCLDEPS_" + lang)) {
// For the MS resource compiler we need cmcldeps, but skip dependencies
// for source-file try_compile cases because they are always fresh.
if (!mf->GetIsSourceFileTryCompile()) {
- deptype = "gcc";
- depfile = "$DEP_FILE";
+ rule.DepType = "gcc";
+ rule.DepFile = "$DEP_FILE";
const std::string cl = mf->GetDefinition("CMAKE_C_COMPILER")
? mf->GetSafeDefinition("CMAKE_C_COMPILER")
: mf->GetSafeDefinition("CMAKE_CXX_COMPILER");
@@ -649,8 +654,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
cldeps += "\" \"" + cl + "\" ";
}
} else {
- deptype = "gcc";
- depfile = "$DEP_FILE";
+ rule.DepType = "gcc";
+ rule.DepFile = "$DEP_FILE";
const std::string flagsName = "CMAKE_DEPFILE_FLAGS_" + lang;
std::string depfileFlags = mf->GetSafeDefinition(flagsName);
if (!depfileFlags.empty()) {
@@ -663,7 +668,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
}
vars.Flags = flags.c_str();
- vars.DependencyFile = depfile.c_str();
+ vars.DependencyFile = rule.DepFile.c_str();
// Rule for compiling object file.
std::vector<std::string> compileCmds;
@@ -671,19 +676,18 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
std::string cmdVar;
if (this->GeneratorTarget->GetPropertyAsBool(
"CUDA_SEPARABLE_COMPILATION")) {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION";
} else if (this->GeneratorTarget->GetPropertyAsBool(
"CUDA_PTX_COMPILATION")) {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_PTX_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION";
} else {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_WHOLE_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION";
}
- std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
+ const std::string& compileCmd = mf->GetRequiredDefinition(cmdVar);
cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
} else {
- const std::string cmdVar =
- std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
- std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
+ const std::string cmdVar = "CMAKE_" + lang + "_COMPILE_OBJECT";
+ const std::string& compileCmd = mf->GetRequiredDefinition(cmdVar);
cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
}
@@ -710,8 +714,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
const char* cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
if ((iwyu && *iwyu) || (tidy && *tidy) || (cpplint && *cpplint) ||
(cppcheck && *cppcheck)) {
- std::string run_iwyu = this->GetLocalGenerator()->ConvertToOutputFormat(
- cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
+ std::string run_iwyu = cmakeCmd;
run_iwyu += " -E __run_co_compile";
if (!compilerLauncher.empty()) {
// In __run_co_compile case the launcher command is supplied
@@ -750,8 +753,12 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
if (!compileCmds.empty() && !compilerLauncher.empty()) {
std::vector<std::string> args;
cmSystemTools::ExpandListArgument(compilerLauncher, args, true);
- for (std::string& i : args) {
- i = this->LocalGenerator->EscapeForShell(i);
+ if (!args.empty()) {
+ args[0] = this->LocalGenerator->ConvertToOutputFormat(
+ args[0], cmOutputConverter::SHELL);
+ for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) {
+ i = this->LocalGenerator->EscapeForShell(i);
+ }
}
compileCmds.front().insert(0, cmJoin(args, " ") + " ");
}
@@ -766,19 +773,16 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
vars);
}
- std::string cmdLine =
- this->GetLocalGenerator()->BuildCommandLine(compileCmds);
+ rule.Command = this->GetLocalGenerator()->BuildCommandLine(compileCmds);
// Write the rule for compiling file of the given language.
- std::ostringstream comment;
- comment << "Rule for compiling " << lang << " files.";
- std::ostringstream description;
- description << "Building " << lang << " object $out";
- this->GetGlobalGenerator()->AddRule(
- this->LanguageCompilerRule(lang), cmdLine, description.str(),
- comment.str(), depfile, deptype, rspfile, rspcontent,
- /*restat*/ "",
- /*generator*/ false);
+ rule.Comment = "Rule for compiling ";
+ rule.Comment += lang;
+ rule.Comment += " files.";
+ rule.Description = "Building ";
+ rule.Description += lang;
+ rule.Description += " object $out";
+ this->GetGlobalGenerator()->AddRule(rule);
}
void cmNinjaTargetGenerator::WriteObjectBuildStatements()
@@ -790,113 +794,141 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements()
<< cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
<< " target " << this->GetTargetName() << "\n\n";
- std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
- std::vector<cmSourceFile const*> customCommands;
- this->GeneratorTarget->GetCustomCommands(customCommands, config);
- for (cmSourceFile const* sf : customCommands) {
- cmCustomCommand const* cc = sf->GetCustomCommand();
- this->GetLocalGenerator()->AddCustomCommandTarget(
- cc, this->GetGeneratorTarget());
- // Record the custom commands for this target. The container is used
- // in WriteObjectBuildStatement when called in a loop below.
- this->CustomCommands.push_back(cc);
+ const std::string& config =
+ this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ {
+ std::vector<cmSourceFile const*> customCommands;
+ this->GeneratorTarget->GetCustomCommands(customCommands, config);
+ for (cmSourceFile const* sf : customCommands) {
+ cmCustomCommand const* cc = sf->GetCustomCommand();
+ this->GetLocalGenerator()->AddCustomCommandTarget(
+ cc, this->GetGeneratorTarget());
+ // Record the custom commands for this target. The container is used
+ // in WriteObjectBuildStatement when called in a loop below.
+ this->CustomCommands.push_back(cc);
+ }
}
- std::vector<cmSourceFile const*> headerSources;
- this->GeneratorTarget->GetHeaderSources(headerSources, config);
- this->OSXBundleGenerator->GenerateMacOSXContentStatements(
- headerSources, this->MacOSXContentGenerator);
- std::vector<cmSourceFile const*> extraSources;
- this->GeneratorTarget->GetExtraSources(extraSources, config);
- this->OSXBundleGenerator->GenerateMacOSXContentStatements(
- extraSources, this->MacOSXContentGenerator);
- std::vector<cmSourceFile const*> externalObjects;
- this->GeneratorTarget->GetExternalObjects(externalObjects, config);
- for (cmSourceFile const* sf : externalObjects) {
- this->Objects.push_back(this->GetSourceFilePath(sf));
+ {
+ std::vector<cmSourceFile const*> headerSources;
+ this->GeneratorTarget->GetHeaderSources(headerSources, config);
+ this->OSXBundleGenerator->GenerateMacOSXContentStatements(
+ headerSources, this->MacOSXContentGenerator.get());
}
-
- cmNinjaDeps orderOnlyDeps;
- this->GetLocalGenerator()->AppendTargetDepends(
- this->GeneratorTarget, orderOnlyDeps, DependOnTargetOrdering);
-
- // Add order-only dependencies on other files associated with the target.
- orderOnlyDeps.insert(orderOnlyDeps.end(), this->ExtraFiles.begin(),
- this->ExtraFiles.end());
-
- // Add order-only dependencies on custom command outputs.
- for (cmCustomCommand const* cc : this->CustomCommands) {
- cmCustomCommandGenerator ccg(*cc, this->GetConfigName(),
- this->GetLocalGenerator());
- const std::vector<std::string>& ccoutputs = ccg.GetOutputs();
- const std::vector<std::string>& ccbyproducts = ccg.GetByproducts();
- std::transform(ccoutputs.begin(), ccoutputs.end(),
- std::back_inserter(orderOnlyDeps), MapToNinjaPath());
- std::transform(ccbyproducts.begin(), ccbyproducts.end(),
- std::back_inserter(orderOnlyDeps), MapToNinjaPath());
+ {
+ std::vector<cmSourceFile const*> extraSources;
+ this->GeneratorTarget->GetExtraSources(extraSources, config);
+ this->OSXBundleGenerator->GenerateMacOSXContentStatements(
+ extraSources, this->MacOSXContentGenerator.get());
}
-
- std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end());
- orderOnlyDeps.erase(std::unique(orderOnlyDeps.begin(), orderOnlyDeps.end()),
- orderOnlyDeps.end());
-
- // The phony target must depend on at least one input or ninja will explain
- // that "output ... of phony edge with no inputs doesn't exist" and consider
- // the phony output "dirty".
- if (orderOnlyDeps.empty()) {
- // Any path that always exists will work here. It would be nice to
- // use just "." but that is not supported by Ninja < 1.7.
- std::string tgtDir;
- tgtDir += this->LocalGenerator->GetCurrentBinaryDirectory();
- tgtDir += "/";
- tgtDir += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
- orderOnlyDeps.push_back(this->ConvertToNinjaPath(tgtDir));
+ {
+ std::vector<cmSourceFile const*> externalObjects;
+ this->GeneratorTarget->GetExternalObjects(externalObjects, config);
+ for (cmSourceFile const* sf : externalObjects) {
+ this->Objects.push_back(this->GetSourceFilePath(sf));
+ }
}
{
- cmNinjaDeps orderOnlyTarget;
- orderOnlyTarget.push_back(this->OrderDependsTargetForTarget());
- this->GetGlobalGenerator()->WritePhonyBuild(
- this->GetBuildFileStream(),
- "Order-only phony target for " + this->GetTargetName(), orderOnlyTarget,
- cmNinjaDeps(), cmNinjaDeps(), orderOnlyDeps);
+ cmNinjaBuild build("phony");
+ build.Comment = "Order-only phony target for " + this->GetTargetName();
+ build.Outputs.push_back(this->OrderDependsTargetForTarget());
+
+ cmNinjaDeps& orderOnlyDeps = build.OrderOnlyDeps;
+ this->GetLocalGenerator()->AppendTargetDepends(
+ this->GeneratorTarget, orderOnlyDeps, DependOnTargetOrdering);
+
+ // Add order-only dependencies on other files associated with the target.
+ cmAppend(orderOnlyDeps, this->ExtraFiles);
+
+ // Add order-only dependencies on custom command outputs.
+ for (cmCustomCommand const* cc : this->CustomCommands) {
+ cmCustomCommandGenerator ccg(*cc, this->GetConfigName(),
+ this->GetLocalGenerator());
+ const std::vector<std::string>& ccoutputs = ccg.GetOutputs();
+ const std::vector<std::string>& ccbyproducts = ccg.GetByproducts();
+ std::transform(ccoutputs.begin(), ccoutputs.end(),
+ std::back_inserter(orderOnlyDeps), MapToNinjaPath());
+ std::transform(ccbyproducts.begin(), ccbyproducts.end(),
+ std::back_inserter(orderOnlyDeps), MapToNinjaPath());
+ }
+
+ std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end());
+ orderOnlyDeps.erase(
+ std::unique(orderOnlyDeps.begin(), orderOnlyDeps.end()),
+ orderOnlyDeps.end());
+
+ // The phony target must depend on at least one input or ninja will explain
+ // that "output ... of phony edge with no inputs doesn't exist" and
+ // consider the phony output "dirty".
+ if (orderOnlyDeps.empty()) {
+ // Any path that always exists will work here. It would be nice to
+ // use just "." but that is not supported by Ninja < 1.7.
+ std::string tgtDir;
+ tgtDir += this->LocalGenerator->GetCurrentBinaryDirectory();
+ tgtDir += "/";
+ tgtDir +=
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ orderOnlyDeps.push_back(this->ConvertToNinjaPath(tgtDir));
+ }
+
+ this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build);
}
- std::vector<cmSourceFile const*> objectSources;
- this->GeneratorTarget->GetObjectSources(objectSources, config);
- for (cmSourceFile const* sf : objectSources) {
- this->WriteObjectBuildStatement(sf);
+
+ {
+ std::vector<cmSourceFile const*> objectSources;
+ this->GeneratorTarget->GetObjectSources(objectSources, config);
+ for (cmSourceFile const* sf : objectSources) {
+ this->WriteObjectBuildStatement(sf);
+ }
}
- if (!this->DDIFiles.empty()) {
- std::string const ddComment;
- std::string const ddRule = this->LanguageDyndepRule("Fortran");
- cmNinjaDeps ddOutputs;
- cmNinjaDeps ddImplicitOuts;
- cmNinjaDeps const& ddExplicitDeps = this->DDIFiles;
- cmNinjaDeps ddImplicitDeps;
- cmNinjaDeps ddOrderOnlyDeps;
- cmNinjaVars ddVars;
+ for (auto const& langDDIFiles : this->DDIFiles) {
+ std::string const& language = langDDIFiles.first;
+ cmNinjaDeps const& ddiFiles = langDDIFiles.second;
- this->WriteTargetDependInfo("Fortran");
+ cmNinjaBuild build(this->LanguageDyndepRule(language));
+ build.Outputs.push_back(this->GetDyndepFilePath(language));
+ build.ExplicitDeps = ddiFiles;
- ddOutputs.push_back(this->GetDyndepFilePath("Fortran"));
+ this->WriteTargetDependInfo(language);
// Make sure dyndep files for all our dependencies have already
- // been generated so that the 'FortranModules.json' files they
+ // been generated so that the '<LANG>Modules.json' files they
// produced as side-effects are available for us to read.
- // Ideally we should depend on the 'FortranModules.json' files
+ // Ideally we should depend on the '<LANG>Modules.json' files
// from our dependencies directly, but we don't know which of
// our dependencies produces them. Fixing this will require
// refactoring the Ninja generator to generate targets in
// dependency order so that we can collect the needed information.
this->GetLocalGenerator()->AppendTargetDepends(
- this->GeneratorTarget, ddOrderOnlyDeps, DependOnTargetArtifact);
+ this->GeneratorTarget, build.OrderOnlyDeps, DependOnTargetArtifact);
- this->GetGlobalGenerator()->WriteBuild(
- this->GetBuildFileStream(), ddComment, ddRule, ddOutputs, ddImplicitOuts,
- ddExplicitDeps, ddImplicitDeps, ddOrderOnlyDeps, ddVars);
+ this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build);
}
this->GetBuildFileStream() << "\n";
+
+ if (!this->SwiftOutputMap.empty()) {
+ std::string const mapFilePath = this->ConvertToNinjaPath(
+ this->GeneratorTarget->GetSupportDirectory() + "/output-file-map.json");
+ std::string const targetSwiftDepsPath = [this]() -> std::string {
+ cmGeneratorTarget const* target = this->GeneratorTarget;
+ if (const char* name = target->GetProperty("Swift_DEPENDENCIES_FILE")) {
+ return name;
+ }
+ return this->ConvertToNinjaPath(target->GetSupportDirectory() + "/" +
+ target->GetName() + ".swiftdeps");
+ }();
+
+ // build the global target dependencies
+ // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps
+ Json::Value deps(Json::objectValue);
+ deps["swift-dependencies"] = targetSwiftDepsPath;
+ this->SwiftOutputMap[""] = deps;
+
+ cmGeneratedFileStream output(mapFilePath);
+ output << this->SwiftOutputMap;
+ }
}
void cmNinjaTargetGenerator::WriteObjectBuildStatement(
@@ -912,36 +944,24 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
std::string const objectFileDir =
cmSystemTools::GetFilenamePath(objectFileName);
+ std::string cmakeVarLang = "CMAKE_";
+ cmakeVarLang += language;
+
+ // build response file name
+ std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_FLAG";
+
+ const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar);
+
bool const lang_supports_response =
- !(language == "RC" || language == "CUDA");
+ !(language == "RC" || (language == "CUDA" && !flag));
int const commandLineLengthLimit =
((lang_supports_response && this->ForceResponseFile())) ? -1 : 0;
- cmNinjaVars vars;
+ cmNinjaBuild objBuild(this->LanguageCompilerRule(language));
+ cmNinjaVars& vars = objBuild.Variables;
vars["FLAGS"] = this->ComputeFlagsForObject(source, language);
vars["DEFINES"] = this->ComputeDefines(source, language);
vars["INCLUDES"] = this->ComputeIncludes(source, language);
- if (language == "Swift") {
- // The swift compiler needs all the sources besides the one being compiled
- // in order to do the type checking. List all these "auxiliary" sources.
- std::string aux_sources;
- cmGeneratorTarget::KindedSources const& sources =
- this->GeneratorTarget->GetKindedSources(this->GetConfigName());
- for (cmGeneratorTarget::SourceAndKind const& src : sources.Sources) {
- if (src.Source.Value == source) {
- continue;
- }
- aux_sources += " " + this->GetSourceFilePath(src.Source.Value);
- }
- vars["SWIFT_AUXILIARY_SOURCES"] = aux_sources;
-
- if (const char* name =
- this->GeneratorTarget->GetProperty("SWIFT_MODULE_NAME")) {
- vars["SWIFT_MODULE_NAME"] = name;
- } else {
- vars["SWIFT_MODULE_NAME"] = this->GeneratorTarget->GetName();
- }
- }
if (!this->NeedDepTypeMSVC(language)) {
bool replaceExt(false);
@@ -969,32 +989,26 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
language, sourceFileName, objectDir, objectFileName, objectFileDir,
vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"]);
- std::string comment;
- std::string rule = this->LanguageCompilerRule(language);
-
- cmNinjaDeps outputs;
- outputs.push_back(objectFileName);
+ objBuild.Outputs.push_back(objectFileName);
// Add this object to the list of object files.
this->Objects.push_back(objectFileName);
- cmNinjaDeps explicitDeps;
- explicitDeps.push_back(sourceFileName);
+ objBuild.ExplicitDeps.push_back(sourceFileName);
- cmNinjaDeps implicitDeps;
if (const char* objectDeps = source->GetProperty("OBJECT_DEPENDS")) {
- std::vector<std::string> depList;
- cmSystemTools::ExpandListArgument(objectDeps, depList);
+ std::vector<std::string> depList =
+ cmSystemTools::ExpandedListArgument(objectDeps);
for (std::string& odi : depList) {
if (cmSystemTools::FileIsFullPath(odi)) {
odi = cmSystemTools::CollapseFullPath(odi);
}
}
std::transform(depList.begin(), depList.end(),
- std::back_inserter(implicitDeps), MapToNinjaPath());
+ std::back_inserter(objBuild.ImplicitDeps),
+ MapToNinjaPath());
}
- cmNinjaDeps orderOnlyDeps;
- orderOnlyDeps.push_back(this->OrderDependsTargetForTarget());
+ objBuild.OrderOnlyDeps.push_back(this->OrderDependsTargetForTarget());
// If the source file is GENERATED and does not have a custom command
// (either attached to this source file or another one), assume that one of
@@ -1004,8 +1018,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
!source->GetPropertyAsBool("__CMAKE_GENERATED_BY_CMAKE") &&
!source->GetCustomCommand() &&
!this->GetGlobalGenerator()->HasCustomCommandOutput(sourceFileName)) {
- this->GetGlobalGenerator()->AddAssumedSourceDependencies(sourceFileName,
- orderOnlyDeps);
+ this->GetGlobalGenerator()->AddAssumedSourceDependencies(
+ sourceFileName, objBuild.OrderOnlyDeps);
}
// For some cases we need to generate a ninja dyndep file.
@@ -1014,89 +1028,101 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
// For some cases we do an explicit preprocessor invocation.
bool const explicitPP = this->NeedExplicitPreprocessing(language);
if (explicitPP) {
- std::string const ppComment;
- std::string const ppRule = this->LanguagePreprocessRule(language);
- cmNinjaDeps ppOutputs;
- cmNinjaDeps ppImplicitOuts;
- cmNinjaDeps ppExplicitDeps;
- cmNinjaDeps ppImplicitDeps;
- cmNinjaDeps ppOrderOnlyDeps;
- cmNinjaVars ppVars;
+ cmNinjaBuild ppBuild(this->LanguagePreprocessRule(language));
std::string const ppFileName =
this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source));
- ppOutputs.push_back(ppFileName);
+ ppBuild.Outputs.push_back(ppFileName);
- // Move compilation dependencies to the preprocessing build statement.
- std::swap(ppExplicitDeps, explicitDeps);
- std::swap(ppImplicitDeps, implicitDeps);
- std::swap(ppOrderOnlyDeps, orderOnlyDeps);
- std::swap(ppVars["IN_ABS"], vars["IN_ABS"]);
+ ppBuild.RspFile = ppFileName + ".rsp";
- // The actual compilation will now use the preprocessed source.
- explicitDeps.push_back(ppFileName);
+ bool const compilePP = this->UsePreprocessedSource(language);
+ if (compilePP) {
+ // Move compilation dependencies to the preprocessing build statement.
+ std::swap(ppBuild.ExplicitDeps, objBuild.ExplicitDeps);
+ std::swap(ppBuild.ImplicitDeps, objBuild.ImplicitDeps);
+ std::swap(ppBuild.OrderOnlyDeps, objBuild.OrderOnlyDeps);
+ std::swap(ppBuild.Variables["IN_ABS"], vars["IN_ABS"]);
- // Preprocessing and compilation generally use the same flags.
- ppVars["FLAGS"] = vars["FLAGS"];
+ // The actual compilation will now use the preprocessed source.
+ objBuild.ExplicitDeps.push_back(ppFileName);
+ } else {
+ // Copy compilation dependencies to the preprocessing build statement.
+ ppBuild.ExplicitDeps = objBuild.ExplicitDeps;
+ ppBuild.ImplicitDeps = objBuild.ImplicitDeps;
+ ppBuild.OrderOnlyDeps = objBuild.OrderOnlyDeps;
+ ppBuild.Variables["IN_ABS"] = vars["IN_ABS"];
+ }
- // In case compilation requires flags that are incompatible with
- // preprocessing, include them here.
- std::string const postFlag =
- this->Makefile->GetSafeDefinition("CMAKE_Fortran_POSTPROCESS_FLAG");
- this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag);
+ // Preprocessing and compilation generally use the same flags.
+ ppBuild.Variables["FLAGS"] = vars["FLAGS"];
+
+ if (compilePP) {
+ // In case compilation requires flags that are incompatible with
+ // preprocessing, include them here.
+ std::string const& postFlag = this->Makefile->GetSafeDefinition(
+ "CMAKE_" + language + "_POSTPROCESS_FLAG");
+ this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag);
+ }
- // Move preprocessor definitions to the preprocessor build statement.
- std::swap(ppVars["DEFINES"], vars["DEFINES"]);
+ if (compilePP) {
+ // Move preprocessor definitions to the preprocessor build statement.
+ std::swap(ppBuild.Variables["DEFINES"], vars["DEFINES"]);
+ } else {
+ // Copy preprocessor definitions to the preprocessor build statement.
+ ppBuild.Variables["DEFINES"] = vars["DEFINES"];
+ }
// Copy include directories to the preprocessor build statement. The
// Fortran compilation build statement still needs them for the INCLUDE
// directive.
- ppVars["INCLUDES"] = vars["INCLUDES"];
+ ppBuild.Variables["INCLUDES"] = vars["INCLUDES"];
- // Prepend source file's original directory as an include directory
- // so e.g. Fortran INCLUDE statements can look for files in it.
- std::vector<std::string> sourceDirectory;
- sourceDirectory.push_back(
- cmSystemTools::GetParentDirectory(source->GetFullPath()));
+ if (compilePP) {
+ // Prepend source file's original directory as an include directory
+ // so e.g. Fortran INCLUDE statements can look for files in it.
+ std::vector<std::string> sourceDirectory;
+ sourceDirectory.push_back(
+ cmSystemTools::GetParentDirectory(source->GetFullPath()));
- std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
- sourceDirectory, this->GeneratorTarget, language, false, false,
- this->GetConfigName());
+ std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
+ sourceDirectory, this->GeneratorTarget, language, false, false,
+ this->GetConfigName());
- vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"];
+ vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"];
+ }
// Explicit preprocessing always uses a depfile.
- ppVars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
- ppFileName + ".d", cmOutputConverter::SHELL);
- // The actual compilation does not need a depfile because it
- // depends on the already-preprocessed source.
- vars.erase("DEP_FILE");
+ ppBuild.Variables["DEP_FILE"] =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ objectFileName + ".pp.d", cmOutputConverter::SHELL);
+ if (compilePP) {
+ // The actual compilation does not need a depfile because it
+ // depends on the already-preprocessed source.
+ vars.erase("DEP_FILE");
+ }
if (needDyndep) {
// Tell dependency scanner the object file that will result from
- // compiling the preprocessed source.
- ppVars["OBJ_FILE"] = objectFileName;
+ // compiling the source.
+ ppBuild.Variables["OBJ_FILE"] = objectFileName;
// Tell dependency scanner where to store dyndep intermediate results.
- std::string const ddiFile = ppFileName + ".ddi";
- ppVars["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
- ppImplicitOuts.push_back(ddiFile);
- this->DDIFiles.push_back(ddiFile);
+ std::string const ddiFile = objectFileName + ".ddi";
+ ppBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
+ ppBuild.ImplicitOuts.push_back(ddiFile);
+ this->DDIFiles[language].push_back(ddiFile);
}
this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
- ppVars);
+ ppBuild.Variables);
- std::string const ppRspFile = ppFileName + ".rsp";
-
- this->GetGlobalGenerator()->WriteBuild(
- this->GetBuildFileStream(), ppComment, ppRule, ppOutputs, ppImplicitOuts,
- ppExplicitDeps, ppImplicitDeps, ppOrderOnlyDeps, ppVars, ppRspFile,
- commandLineLengthLimit);
+ this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), ppBuild,
+ commandLineLengthLimit);
}
if (needDyndep) {
std::string const dyndep = this->GetDyndepFilePath(language);
- orderOnlyDeps.push_back(dyndep);
+ objBuild.OrderOnlyDeps.push_back(dyndep);
vars["dyndep"] = dyndep;
}
@@ -1112,21 +1138,23 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
this->SetMsvcTargetPdbVariable(vars);
- std::string const rspfile = objectFileName + ".rsp";
+ objBuild.RspFile = objectFileName + ".rsp";
- this->GetGlobalGenerator()->WriteBuild(
- this->GetBuildFileStream(), comment, rule, outputs,
- /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps, orderOnlyDeps,
- vars, rspfile, commandLineLengthLimit);
+ if (language == "Swift") {
+ this->EmitSwiftDependencyInfo(source);
+ } else {
+ this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(),
+ objBuild, commandLineLengthLimit);
+ }
if (const char* objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) {
- std::vector<std::string> outputList;
- cmSystemTools::ExpandListArgument(objectOutputs, outputList);
- std::transform(outputList.begin(), outputList.end(), outputList.begin(),
- MapToNinjaPath());
- this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(),
- "Additional output files.",
- outputList, outputs);
+ cmNinjaBuild build("phony");
+ build.Comment = "Additional output files.";
+ build.Outputs = cmSystemTools::ExpandedListArgument(objectOutputs);
+ std::transform(build.Outputs.begin(), build.Outputs.end(),
+ build.Outputs.begin(), MapToNinjaPath());
+ build.ExplicitDeps = objBuild.Outputs;
+ this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build);
}
}
@@ -1167,8 +1195,7 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang)
Json::Value& tdi_linked_target_dirs = tdi["linked-target-dirs"] =
Json::arrayValue;
- std::vector<std::string> linked = this->GetLinkedTargetDirectories();
- for (std::string const& l : linked) {
+ for (std::string const& l : this->GetLinkedTargetDirectories()) {
tdi_linked_target_dirs.append(l);
}
@@ -1177,6 +1204,52 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang)
tdif << tdi;
}
+void cmNinjaTargetGenerator::EmitSwiftDependencyInfo(
+ cmSourceFile const* source)
+{
+ std::string const sourceFilePath =
+ this->ConvertToNinjaPath(this->GetSourceFilePath(source));
+ std::string const objectFilePath =
+ this->ConvertToNinjaPath(this->GetObjectFilePath(source));
+ std::string const swiftDepsPath = [source, objectFilePath]() -> std::string {
+ if (const char* name = source->GetProperty("Swift_DEPENDENCIES_FILE")) {
+ return name;
+ }
+ return objectFilePath + ".swiftdeps";
+ }();
+ std::string const swiftDiaPath = [source, objectFilePath]() -> std::string {
+ if (const char* name = source->GetProperty("Swift_DIAGNOSTICS_FILE")) {
+ return name;
+ }
+ return objectFilePath + ".dia";
+ }();
+ std::string const makeDepsPath = [this, source]() -> std::string {
+ cmLocalNinjaGenerator const* local = this->GetLocalGenerator();
+ std::string const objectFileName =
+ this->ConvertToNinjaPath(this->GetObjectFilePath(source));
+ std::string const objectFileDir =
+ cmSystemTools::GetFilenamePath(objectFileName);
+
+ if (this->Makefile->IsOn("CMAKE_Swift_DEPFLE_EXTNSION_REPLACE")) {
+ std::string dependFileName =
+ cmSystemTools::GetFilenameWithoutLastExtension(objectFileName) + ".d";
+ return local->ConvertToOutputFormat(objectFileDir + "/" + dependFileName,
+ cmOutputConverter::SHELL);
+ }
+ return local->ConvertToOutputFormat(objectFileName + ".d",
+ cmOutputConverter::SHELL);
+ }();
+
+ // build the source file mapping
+ // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps
+ Json::Value entry = Json::Value(Json::objectValue);
+ entry["object"] = objectFilePath;
+ entry["dependencies"] = makeDepsPath;
+ entry["swift-dependencies"] = swiftDepsPath;
+ entry["diagnostics"] = swiftDiaPath;
+ SwiftOutputMap[sourceFilePath] = entry;
+}
+
void cmNinjaTargetGenerator::ExportObjectCompileCommand(
std::string const& language, std::string const& sourceFileName,
std::string const& objectDir, std::string const& objectFileName,
@@ -1217,20 +1290,19 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand(
std::string cmdVar;
if (this->GeneratorTarget->GetPropertyAsBool(
"CUDA_SEPARABLE_COMPILATION")) {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION";
} else if (this->GeneratorTarget->GetPropertyAsBool(
"CUDA_PTX_COMPILATION")) {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_PTX_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION";
} else {
- cmdVar = std::string("CMAKE_CUDA_COMPILE_WHOLE_COMPILATION");
+ cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION";
}
- std::string compileCmd =
+ const std::string& compileCmd =
this->GetMakefile()->GetRequiredDefinition(cmdVar);
cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
} else {
- const std::string cmdVar =
- std::string("CMAKE_") + language + "_COMPILE_OBJECT";
- std::string compileCmd =
+ const std::string cmdVar = "CMAKE_" + language + "_COMPILE_OBJECT";
+ const std::string& compileCmd =
this->GetMakefile()->GetRequiredDefinition(cmdVar);
cmSystemTools::ExpandListArgument(compileCmd, compileCmds);
}
@@ -1250,6 +1322,31 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand(
this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName);
}
+void cmNinjaTargetGenerator::AdditionalCleanFiles()
+{
+ if (const char* prop_value =
+ this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) {
+ cmLocalNinjaGenerator* lg = this->LocalGenerator;
+ std::vector<std::string> cleanFiles;
+ {
+ cmGeneratorExpression ge;
+ auto cge = ge.Parse(prop_value);
+ cmSystemTools::ExpandListArgument(
+ cge->Evaluate(lg,
+ this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"),
+ false, this->GeneratorTarget, nullptr, nullptr),
+ cleanFiles);
+ }
+ std::string const& binaryDir = lg->GetCurrentBinaryDirectory();
+ cmGlobalNinjaGenerator* gg = lg->GetGlobalNinjaGenerator();
+ for (std::string const& cleanFile : cleanFiles) {
+ // Support relative paths
+ gg->AddAdditionalCleanFile(
+ cmSystemTools::CollapseFullPath(cleanFile, binaryDir));
+ }
+ }
+}
+
void cmNinjaTargetGenerator::EnsureDirectoryExists(
const std::string& path) const
{
@@ -1257,8 +1354,7 @@ void cmNinjaTargetGenerator::EnsureDirectoryExists(
cmSystemTools::MakeDirectory(path);
} else {
cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator();
- std::string fullPath =
- std::string(gg->GetCMakeInstance()->GetHomeOutputDirectory());
+ std::string fullPath = gg->GetCMakeInstance()->GetHomeOutputDirectory();
// Also ensures their is a trailing slash.
gg->StripNinjaOutputPathPrefixAsSuffix(fullPath);
fullPath += path;
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 373c693bf..3055e18c3 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -5,11 +5,15 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cm_jsoncpp_value.h"
+
#include "cmCommonTargetGenerator.h"
#include "cmGlobalNinjaGenerator.h"
#include "cmNinjaTypes.h"
#include "cmOSXBundleGenerator.h"
+#include <map>
+#include <memory> // IWYU pragma: keep
#include <set>
#include <string>
#include <vector>
@@ -25,7 +29,8 @@ class cmNinjaTargetGenerator : public cmCommonTargetGenerator
{
public:
/// Create a cmNinjaTargetGenerator according to the @a target's type.
- static cmNinjaTargetGenerator* New(cmGeneratorTarget* target);
+ static std::unique_ptr<cmNinjaTargetGenerator> New(
+ cmGeneratorTarget* target);
/// Build a NinjaTargetGenerator.
cmNinjaTargetGenerator(cmGeneratorTarget* target);
@@ -64,6 +69,7 @@ protected:
bool NeedExplicitPreprocessing(std::string const& lang) const;
std::string LanguageDyndepRule(std::string const& lang) const;
bool NeedDyndep(std::string const& lang) const;
+ bool UsePreprocessedSource(std::string const& lang) const;
std::string OrderDependsTargetForTarget();
@@ -124,12 +130,16 @@ protected:
void WriteObjectBuildStatement(cmSourceFile const* source);
void WriteTargetDependInfo(std::string const& lang);
+ void EmitSwiftDependencyInfo(cmSourceFile const* source);
+
void ExportObjectCompileCommand(
std::string const& language, std::string const& sourceFileName,
std::string const& objectDir, std::string const& objectFileName,
std::string const& objectFileDir, std::string const& flags,
std::string const& defines, std::string const& includes);
+ void AdditionalCleanFiles();
+
cmNinjaDeps GetObjects() const { return this->Objects; }
void EnsureDirectoryExists(const std::string& dir) const;
@@ -151,9 +161,9 @@ protected:
};
friend struct MacOSXContentGeneratorType;
- MacOSXContentGeneratorType* MacOSXContentGenerator;
+ std::unique_ptr<MacOSXContentGeneratorType> MacOSXContentGenerator;
// Properly initialized by sub-classes.
- cmOSXBundleGenerator* OSXBundleGenerator;
+ std::unique_ptr<cmOSXBundleGenerator> OSXBundleGenerator;
std::set<std::string> MacContentFolders;
void addPoolNinjaVariable(const std::string& pool_property,
@@ -165,7 +175,10 @@ private:
cmLocalNinjaGenerator* LocalGenerator;
/// List of object files for this target.
cmNinjaDeps Objects;
- cmNinjaDeps DDIFiles; // TODO: Make per-language.
+ // Fortran Support
+ std::map<std::string, cmNinjaDeps> DDIFiles;
+ // Swift Support
+ Json::Value SwiftOutputMap;
std::vector<cmCustomCommand const*> CustomCommands;
cmNinjaDeps ExtraFiles;
};
diff --git a/Source/cmNinjaTypes.h b/Source/cmNinjaTypes.h
index 9e962f135..52c05b62c 100644
--- a/Source/cmNinjaTypes.h
+++ b/Source/cmNinjaTypes.h
@@ -8,6 +8,7 @@
#include <map>
#include <set>
#include <string>
+#include <utility>
#include <vector>
enum cmNinjaTargetDepends
@@ -20,4 +21,44 @@ typedef std::vector<std::string> cmNinjaDeps;
typedef std::set<std::string> cmNinjaOuts;
typedef std::map<std::string, std::string> cmNinjaVars;
+class cmNinjaRule
+{
+public:
+ cmNinjaRule(std::string name)
+ : Name(std::move(name))
+ {
+ }
+
+ std::string Name;
+ std::string Command;
+ std::string Description;
+ std::string Comment;
+ std::string DepFile;
+ std::string DepType;
+ std::string RspFile;
+ std::string RspContent;
+ std::string Restat;
+ bool Generator = false;
+};
+
+class cmNinjaBuild
+{
+public:
+ cmNinjaBuild() = default;
+ cmNinjaBuild(std::string rule)
+ : Rule(std::move(rule))
+ {
+ }
+
+ std::string Comment;
+ std::string Rule;
+ cmNinjaDeps Outputs;
+ cmNinjaDeps ImplicitOuts;
+ cmNinjaDeps ExplicitDeps;
+ cmNinjaDeps ImplicitDeps;
+ cmNinjaDeps OrderOnlyDeps;
+ cmNinjaVars Variables;
+ std::string RspFile;
+};
+
#endif // ! cmNinjaTypes_h
diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx
index 95fcf66f4..1225cbdf3 100644
--- a/Source/cmNinjaUtilityTargetGenerator.cxx
+++ b/Source/cmNinjaUtilityTargetGenerator.cxx
@@ -16,8 +16,10 @@
#include "cmSystemTools.h"
#include <algorithm>
+#include <array>
#include <iterator>
#include <string>
+#include <utility>
#include <vector>
cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator(
@@ -30,74 +32,74 @@ cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() = default;
void cmNinjaUtilityTargetGenerator::Generate()
{
- std::string utilCommandName =
- this->GetLocalGenerator()->GetCurrentBinaryDirectory();
+ cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator();
+ cmLocalNinjaGenerator* lg = this->GetLocalGenerator();
+ cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
+
+ std::string utilCommandName = lg->GetCurrentBinaryDirectory();
utilCommandName += "/CMakeFiles";
utilCommandName += "/";
utilCommandName += this->GetTargetName() + ".util";
utilCommandName = this->ConvertToNinjaPath(utilCommandName);
+ cmNinjaBuild phonyBuild("phony");
std::vector<std::string> commands;
- cmNinjaDeps deps, outputs, util_outputs(1, utilCommandName);
-
- const std::vector<cmCustomCommand>* cmdLists[2] = {
- &this->GetGeneratorTarget()->GetPreBuildCommands(),
- &this->GetGeneratorTarget()->GetPostBuildCommands()
- };
+ cmNinjaDeps deps, util_outputs(1, utilCommandName);
bool uses_terminal = false;
-
- for (unsigned i = 0; i != 2; ++i) {
- for (cmCustomCommand const& ci : *cmdLists[i]) {
- cmCustomCommandGenerator ccg(ci, this->GetConfigName(),
- this->GetLocalGenerator());
- this->GetLocalGenerator()->AppendCustomCommandDeps(ccg, deps);
- this->GetLocalGenerator()->AppendCustomCommandLines(ccg, commands);
- std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
- std::transform(ccByproducts.begin(), ccByproducts.end(),
- std::back_inserter(util_outputs), MapToNinjaPath());
- if (ci.GetUsesTerminal()) {
- uses_terminal = true;
+ {
+ std::array<std::vector<cmCustomCommand> const*, 2> const cmdLists = {
+ { &genTarget->GetPreBuildCommands(), &genTarget->GetPostBuildCommands() }
+ };
+
+ for (std::vector<cmCustomCommand> const* cmdList : cmdLists) {
+ for (cmCustomCommand const& ci : *cmdList) {
+ cmCustomCommandGenerator ccg(ci, this->GetConfigName(), lg);
+ lg->AppendCustomCommandDeps(ccg, deps);
+ lg->AppendCustomCommandLines(ccg, commands);
+ std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
+ std::transform(ccByproducts.begin(), ccByproducts.end(),
+ std::back_inserter(util_outputs), MapToNinjaPath());
+ if (ci.GetUsesTerminal()) {
+ uses_terminal = true;
+ }
}
}
}
- std::vector<cmSourceFile*> sources;
- std::string config =
- this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
- this->GetGeneratorTarget()->GetSourceFiles(sources, config);
- for (cmSourceFile const* source : sources) {
- if (cmCustomCommand const* cc = source->GetCustomCommand()) {
- cmCustomCommandGenerator ccg(*cc, this->GetConfigName(),
- this->GetLocalGenerator());
- this->GetLocalGenerator()->AddCustomCommandTarget(
- cc, this->GetGeneratorTarget());
-
- // Depend on all custom command outputs.
- const std::vector<std::string>& ccOutputs = ccg.GetOutputs();
- const std::vector<std::string>& ccByproducts = ccg.GetByproducts();
- std::transform(ccOutputs.begin(), ccOutputs.end(),
- std::back_inserter(deps), MapToNinjaPath());
- std::transform(ccByproducts.begin(), ccByproducts.end(),
- std::back_inserter(deps), MapToNinjaPath());
+ {
+ std::string const& config =
+ this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ std::vector<cmSourceFile*> sources;
+ genTarget->GetSourceFiles(sources, config);
+ for (cmSourceFile const* source : sources) {
+ if (cmCustomCommand const* cc = source->GetCustomCommand()) {
+ cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), lg);
+ lg->AddCustomCommandTarget(cc, genTarget);
+
+ // Depend on all custom command outputs.
+ const std::vector<std::string>& ccOutputs = ccg.GetOutputs();
+ const std::vector<std::string>& ccByproducts = ccg.GetByproducts();
+ std::transform(ccOutputs.begin(), ccOutputs.end(),
+ std::back_inserter(deps), MapToNinjaPath());
+ std::transform(ccByproducts.begin(), ccByproducts.end(),
+ std::back_inserter(deps), MapToNinjaPath());
+ }
}
}
- this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
- outputs);
- this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(),
- deps);
+ lg->AppendTargetOutputs(genTarget, phonyBuild.Outputs);
+ lg->AppendTargetDepends(genTarget, deps);
if (commands.empty()) {
- this->GetGlobalGenerator()->WritePhonyBuild(
- this->GetBuildFileStream(),
- "Utility command for " + this->GetTargetName(), outputs, deps);
+ phonyBuild.Comment = "Utility command for " + this->GetTargetName();
+ phonyBuild.ExplicitDeps = std::move(deps);
+ gg->WriteBuild(this->GetBuildFileStream(), phonyBuild);
} else {
- std::string command = this->GetLocalGenerator()->BuildCommandLine(
- commands, "utility", this->GeneratorTarget);
- const char* echoStr =
- this->GetGeneratorTarget()->GetProperty("EchoString");
+ std::string command =
+ lg->BuildCommandLine(commands, "utility", this->GeneratorTarget);
std::string desc;
+ const char* echoStr = genTarget->GetProperty("EchoString");
if (echoStr) {
desc = echoStr;
} else {
@@ -108,18 +110,12 @@ void cmNinjaUtilityTargetGenerator::Generate()
// makefile vars.
cmSystemTools::ReplaceString(
command, "$(CMAKE_SOURCE_DIR)",
- this->GetLocalGenerator()
- ->ConvertToOutputFormat(
- this->GetLocalGenerator()->GetSourceDirectory(),
- cmOutputConverter::SHELL)
- .c_str());
+ lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
+ cmOutputConverter::SHELL));
cmSystemTools::ReplaceString(
command, "$(CMAKE_BINARY_DIR)",
- this->GetLocalGenerator()
- ->ConvertToOutputFormat(
- this->GetLocalGenerator()->GetBinaryDirectory(),
- cmOutputConverter::SHELL)
- .c_str());
+ lg->ConvertToOutputFormat(lg->GetBinaryDirectory(),
+ cmOutputConverter::SHELL));
cmSystemTools::ReplaceString(command, "$(ARGS)", "");
if (command.find('$') != std::string::npos) {
@@ -127,24 +123,22 @@ void cmNinjaUtilityTargetGenerator::Generate()
}
for (std::string const& util_output : util_outputs) {
- this->GetGlobalGenerator()->SeenCustomCommandOutput(util_output);
+ gg->SeenCustomCommandOutput(util_output);
}
- this->GetGlobalGenerator()->WriteCustomCommandBuild(
- command, desc, "Utility command for " + this->GetTargetName(),
- /*depfile*/ "", uses_terminal,
- /*restat*/ true, util_outputs, deps);
+ gg->WriteCustomCommandBuild(command, desc,
+ "Utility command for " + this->GetTargetName(),
+ /*depfile*/ "", /*job_pool*/ "", uses_terminal,
+ /*restat*/ true, util_outputs, deps);
- this->GetGlobalGenerator()->WritePhonyBuild(
- this->GetBuildFileStream(), "", outputs,
- cmNinjaDeps(1, utilCommandName));
+ phonyBuild.ExplicitDeps.push_back(utilCommandName);
+ gg->WriteBuild(this->GetBuildFileStream(), phonyBuild);
}
// Add an alias for the logical target name regardless of what directory
// contains it. Skip this for GLOBAL_TARGET because they are meant to
// be per-directory and have one at the top-level anyway.
- if (this->GetGeneratorTarget()->GetType() != cmStateEnums::GLOBAL_TARGET) {
- this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
- this->GetGeneratorTarget());
+ if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
+ gg->AddTargetAlias(this->GetTargetName(), genTarget);
}
}
diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx
index 6857d5a27..47a8df4ef 100644
--- a/Source/cmOSXBundleGenerator.cxx
+++ b/Source/cmOSXBundleGenerator.cxx
@@ -54,8 +54,7 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName,
plist += this->GT->GetAppBundleDirectory(this->ConfigName,
cmGeneratorTarget::ContentLevel);
plist += "/Info.plist";
- this->LocalGenerator->GenerateAppleInfoPList(this->GT, targetName,
- plist.c_str());
+ this->LocalGenerator->GenerateAppleInfoPList(this->GT, targetName, plist);
this->Makefile->AddCMakeOutputFile(plist);
outpath = out;
}
@@ -90,8 +89,7 @@ void cmOSXBundleGenerator::CreateFramework(const std::string& targetName,
}
plist += "/Info.plist";
std::string name = cmSystemTools::GetFilenameName(targetName);
- this->LocalGenerator->GenerateFrameworkInfoPList(this->GT, name,
- plist.c_str());
+ this->LocalGenerator->GenerateFrameworkInfoPList(this->GT, name, plist);
// Generate Versions directory only for MacOSX frameworks
if (this->Makefile->PlatformIsAppleEmbedded()) {
@@ -184,7 +182,7 @@ void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName,
cmGeneratorTarget::ContentLevel);
plist += "/Info.plist";
std::string name = cmSystemTools::GetFilenameName(targetName);
- this->LocalGenerator->GenerateAppleInfoPList(this->GT, name, plist.c_str());
+ this->LocalGenerator->GenerateAppleInfoPList(this->GT, name, plist);
this->Makefile->AddCMakeOutputFile(plist);
}
diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx
index 2c28fc0b7..585db423e 100644
--- a/Source/cmOrderDirectories.cxx
+++ b/Source/cmOrderDirectories.cxx
@@ -329,15 +329,13 @@ void cmOrderDirectories::AddLinkLibrary(std::string const& fullPath)
void cmOrderDirectories::AddUserDirectories(
std::vector<std::string> const& extra)
{
- this->UserDirectories.insert(this->UserDirectories.end(), extra.begin(),
- extra.end());
+ cmAppend(this->UserDirectories, extra);
}
void cmOrderDirectories::AddLanguageDirectories(
std::vector<std::string> const& dirs)
{
- this->LanguageDirectories.insert(this->LanguageDirectories.end(),
- dirs.begin(), dirs.end());
+ cmAppend(this->LanguageDirectories, dirs);
}
void cmOrderDirectories::SetImplicitDirectories(
diff --git a/Source/cmOrderDirectories.h b/Source/cmOrderDirectories.h
index 5916f7ab4..23e61d678 100644
--- a/Source/cmOrderDirectories.h
+++ b/Source/cmOrderDirectories.h
@@ -25,6 +25,8 @@ public:
cmOrderDirectories(cmGlobalGenerator* gg, cmGeneratorTarget const* target,
const char* purpose);
~cmOrderDirectories();
+ cmOrderDirectories(const cmOrderDirectories&) = delete;
+ cmOrderDirectories& operator=(const cmOrderDirectories&) = delete;
void AddRuntimeLibrary(std::string const& fullPath,
const char* soname = nullptr);
void AddLinkLibrary(std::string const& fullPath);
diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h
index 6438c7bad..deca767c6 100644
--- a/Source/cmOutputConverter.h
+++ b/Source/cmOutputConverter.h
@@ -27,7 +27,7 @@ public:
std::string ConvertDirectorySeparatorsForShell(
const std::string& source) const;
- ///! for existing files convert to output path and short path if spaces
+ //! for existing files convert to output path and short path if spaces
std::string ConvertToOutputForExisting(const std::string& remote,
OutputFormat format = SHELL) const;
diff --git a/Source/cmOutputRequiredFilesCommand.cxx b/Source/cmOutputRequiredFilesCommand.cxx
index 46d04a65f..f3276ecd6 100644
--- a/Source/cmOutputRequiredFilesCommand.cxx
+++ b/Source/cmOutputRequiredFilesCommand.cxx
@@ -92,6 +92,9 @@ public:
*/
~cmLBDepend() { cmDeleteAll(this->DependInformationMap); }
+ cmLBDepend(const cmLBDepend&) = delete;
+ cmLBDepend& operator=(const cmLBDepend&) = delete;
+
/**
* Set the makefile that is used as a source of classes.
*/
@@ -108,8 +111,7 @@ public:
// Now extract any include paths from the targets
std::set<std::string> uniqueIncludes;
std::vector<std::string> orderedAndUniqueIncludes;
- cmTargets& targets = this->Makefile->GetTargets();
- for (auto const& target : targets) {
+ for (auto const& target : this->Makefile->GetTargets()) {
const char* incDirProp =
target.second.GetProperty("INCLUDE_DIRECTORIES");
if (!incDirProp) {
@@ -163,7 +165,7 @@ protected:
{
cmsys::ifstream fin(info->FullPath.c_str());
if (!fin) {
- cmSystemTools::Error("error can not open ", info->FullPath.c_str());
+ cmSystemTools::Error("error can not open " + info->FullPath);
return;
}
@@ -178,7 +180,7 @@ protected:
qstart = line.find('<', 8);
// if a < is not found then move on
if (qstart == std::string::npos) {
- cmSystemTools::Error("unknown include directive ", line.c_str());
+ cmSystemTools::Error("unknown include directive " + line);
continue;
}
qend = line.find('>', qstart + 1);
@@ -290,8 +292,8 @@ protected:
// Make sure we don't visit the same file more than once.
info->DependDone = true;
- const char* path = info->FullPath.c_str();
- if (!path) {
+ const std::string& path = info->FullPath;
+ if (path.empty()) {
cmSystemTools::Error(
"Attempt to find dependencies for file without path!");
return;
@@ -353,7 +355,7 @@ protected:
if (!found) {
// Couldn't find any dependency information.
if (this->ComplainFileRegularExpression.find(info->IncludeName)) {
- cmSystemTools::Error("error cannot find dependencies for ", path);
+ cmSystemTools::Error("error cannot find dependencies for " + path);
} else {
// Destroy the name of the file so that it won't be output as a
// dependency.
diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx
index 796974cb3..521343203 100644
--- a/Source/cmParseArgumentsCommand.cxx
+++ b/Source/cmParseArgumentsCommand.cxx
@@ -8,13 +8,16 @@
#include <utility>
#include "cmAlgorithms.h"
+#include "cmArgumentParser.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
+#include "cm_string_view.hxx"
class cmExecutionStatus;
-static std::string escape_arg(const std::string& arg)
+static std::string EscapeArg(const std::string& arg)
{
// replace ";" with "\;" so output argument lists will split correctly
std::string escapedArg;
@@ -27,6 +30,82 @@ static std::string escape_arg(const std::string& arg)
return escapedArg;
}
+static std::string JoinList(std::vector<std::string> const& arg, bool escape)
+{
+ return escape ? cmJoin(cmMakeRange(arg).transform(EscapeArg), ";")
+ : cmJoin(cmMakeRange(arg), ";");
+}
+
+namespace {
+
+typedef std::map<std::string, bool> options_map;
+typedef std::map<std::string, std::string> single_map;
+typedef std::map<std::string, std::vector<std::string>> multi_map;
+typedef std::set<std::string> options_set;
+
+struct UserArgumentParser : public cmArgumentParser<void>
+{
+ template <typename T, typename H>
+ void Bind(std::vector<std::string> const& names,
+ std::map<std::string, T>& ref, H duplicateKey)
+ {
+ for (std::string const& key : names) {
+ auto const it = ref.emplace(key, T{}).first;
+ bool const inserted = this->cmArgumentParser<void>::Bind(
+ cm::string_view(it->first), it->second);
+ if (!inserted) {
+ duplicateKey(key);
+ }
+ }
+ }
+};
+
+} // namespace
+
+static void PassParsedArguments(
+ const std::string& prefix, cmMakefile& makefile, const options_map& options,
+ const single_map& singleValArgs, const multi_map& multiValArgs,
+ const std::vector<std::string>& unparsed,
+ const options_set& keywordsMissingValues, bool parseFromArgV)
+{
+ for (auto const& iter : options) {
+ makefile.AddDefinition(prefix + iter.first,
+ iter.second ? "TRUE" : "FALSE");
+ }
+
+ for (auto const& iter : singleValArgs) {
+ if (!iter.second.empty()) {
+ makefile.AddDefinition(prefix + iter.first, iter.second.c_str());
+ } else {
+ makefile.RemoveDefinition(prefix + iter.first);
+ }
+ }
+
+ for (auto const& iter : multiValArgs) {
+ if (!iter.second.empty()) {
+ makefile.AddDefinition(prefix + iter.first,
+ JoinList(iter.second, parseFromArgV).c_str());
+ } else {
+ makefile.RemoveDefinition(prefix + iter.first);
+ }
+ }
+
+ if (!unparsed.empty()) {
+ makefile.AddDefinition(prefix + "UNPARSED_ARGUMENTS",
+ JoinList(unparsed, parseFromArgV).c_str());
+ } else {
+ makefile.RemoveDefinition(prefix + "UNPARSED_ARGUMENTS");
+ }
+
+ if (!keywordsMissingValues.empty()) {
+ makefile.AddDefinition(
+ prefix + "KEYWORDS_MISSING_VALUES",
+ cmJoin(cmMakeRange(keywordsMissingValues), ";").c_str());
+ } else {
+ makefile.RemoveDefinition(prefix + "KEYWORDS_MISSING_VALUES");
+ }
+}
+
bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
cmExecutionStatus&)
{
@@ -65,11 +144,10 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
// the first argument is the prefix
const std::string prefix = (*argIter++) + "_";
+ UserArgumentParser parser;
+
// define the result maps holding key/value pairs for
// options, single values and multi values
- typedef std::map<std::string, bool> options_map;
- typedef std::map<std::string, std::string> single_map;
- typedef std::map<std::string, std::vector<std::string>> multi_map;
options_map options;
single_map singleValArgs;
multi_map multiValArgs;
@@ -77,50 +155,25 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
// anything else is put into a vector of unparsed strings
std::vector<std::string> unparsed;
- // remember already defined keywords
- std::set<std::string> used_keywords;
- const std::string dup_warning = "keyword defined more than once: ";
+ auto const duplicateKey = [this](std::string const& key) {
+ this->GetMakefile()->IssueMessage(
+ MessageType::WARNING, "keyword defined more than once: " + key);
+ };
// the second argument is a (cmake) list of options without argument
std::vector<std::string> list;
cmSystemTools::ExpandListArgument(*argIter++, list);
- for (std::string const& iter : list) {
- if (!used_keywords.insert(iter).second) {
- this->GetMakefile()->IssueMessage(MessageType::WARNING,
- dup_warning + iter);
- }
- options[iter]; // default initialize
- }
+ parser.Bind(list, options, duplicateKey);
// the third argument is a (cmake) list of single argument options
list.clear();
cmSystemTools::ExpandListArgument(*argIter++, list);
- for (std::string const& iter : list) {
- if (!used_keywords.insert(iter).second) {
- this->GetMakefile()->IssueMessage(MessageType::WARNING,
- dup_warning + iter);
- }
- singleValArgs[iter]; // default initialize
- }
+ parser.Bind(list, singleValArgs, duplicateKey);
// the fourth argument is a (cmake) list of multi argument options
list.clear();
cmSystemTools::ExpandListArgument(*argIter++, list);
- for (std::string const& iter : list) {
- if (!used_keywords.insert(iter).second) {
- this->GetMakefile()->IssueMessage(MessageType::WARNING,
- dup_warning + iter);
- }
- multiValArgs[iter]; // default initialize
- }
-
- enum insideValues
- {
- NONE,
- SINGLE,
- MULTI
- } insideValues = NONE;
- std::string currentArgName;
+ parser.Bind(list, multiValArgs, duplicateKey);
list.clear();
if (!parseFromArgV) {
@@ -155,81 +208,14 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
}
}
- // iterate over the arguments list and fill in the values where applicable
- for (std::string const& arg : list) {
- const options_map::iterator optIter = options.find(arg);
- if (optIter != options.end()) {
- insideValues = NONE;
- optIter->second = true;
- continue;
- }
-
- const single_map::iterator singleIter = singleValArgs.find(arg);
- if (singleIter != singleValArgs.end()) {
- insideValues = SINGLE;
- currentArgName = arg;
- continue;
- }
-
- const multi_map::iterator multiIter = multiValArgs.find(arg);
- if (multiIter != multiValArgs.end()) {
- insideValues = MULTI;
- currentArgName = arg;
- continue;
- }
-
- switch (insideValues) {
- case SINGLE:
- singleValArgs[currentArgName] = arg;
- insideValues = NONE;
- break;
- case MULTI:
- if (parseFromArgV) {
- multiValArgs[currentArgName].push_back(escape_arg(arg));
- } else {
- multiValArgs[currentArgName].push_back(arg);
- }
- break;
- default:
- if (parseFromArgV) {
- unparsed.push_back(escape_arg(arg));
- } else {
- unparsed.push_back(arg);
- }
- break;
- }
- }
+ std::vector<std::string> keywordsMissingValues;
- // now iterate over the collected values and update their definition
- // within the current scope. undefine if necessary.
+ parser.Parse(list, &unparsed, &keywordsMissingValues);
- for (auto const& iter : options) {
- this->Makefile->AddDefinition(prefix + iter.first,
- iter.second ? "TRUE" : "FALSE");
- }
- for (auto const& iter : singleValArgs) {
- if (!iter.second.empty()) {
- this->Makefile->AddDefinition(prefix + iter.first, iter.second.c_str());
- } else {
- this->Makefile->RemoveDefinition(prefix + iter.first);
- }
- }
-
- for (auto const& iter : multiValArgs) {
- if (!iter.second.empty()) {
- this->Makefile->AddDefinition(
- prefix + iter.first, cmJoin(cmMakeRange(iter.second), ";").c_str());
- } else {
- this->Makefile->RemoveDefinition(prefix + iter.first);
- }
- }
-
- if (!unparsed.empty()) {
- this->Makefile->AddDefinition(prefix + "UNPARSED_ARGUMENTS",
- cmJoin(cmMakeRange(unparsed), ";").c_str());
- } else {
- this->Makefile->RemoveDefinition(prefix + "UNPARSED_ARGUMENTS");
- }
+ PassParsedArguments(
+ prefix, *this->Makefile, options, singleValArgs, multiValArgs, unparsed,
+ options_set(keywordsMissingValues.begin(), keywordsMissingValues.end()),
+ parseFromArgV);
return true;
}
diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx
index 0a234c52e..ec4013629 100644
--- a/Source/cmPolicies.cxx
+++ b/Source/cmPolicies.cxx
@@ -145,7 +145,7 @@ static bool GetPolicyDefault(cmMakefile* mf, std::string const& policy,
} else {
std::ostringstream e;
e << defaultVar << " has value \"" << defaultValue
- << "\" but must be \"OLD\", \"NEW\", or \"\" (empty).";
+ << R"(" but must be "OLD", "NEW", or "" (empty).)";
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
return false;
}
@@ -299,7 +299,7 @@ bool cmPolicies::GetPolicyID(const char* id, cmPolicies::PolicyID& pid)
return stringToId(id, pid);
}
-///! return a warning string for a given policy
+//! return a warning string for a given policy
std::string cmPolicies::GetPolicyWarning(cmPolicies::PolicyID id)
{
std::ostringstream msg;
@@ -333,7 +333,7 @@ std::string cmPolicies::GetPolicyDeprecatedWarning(cmPolicies::PolicyID id)
return msg.str();
}
-///! return an error string for when a required policy is unspecified
+//! return an error string for when a required policy is unspecified
std::string cmPolicies::GetRequiredPolicyError(cmPolicies::PolicyID id)
{
std::ostringstream error;
@@ -359,7 +359,7 @@ std::string cmPolicies::GetRequiredPolicyError(cmPolicies::PolicyID id)
return error.str();
}
-///! Get the default status for a policy
+//! Get the default status for a policy
cmPolicies::PolicyStatus cmPolicies::GetPolicyStatus(
cmPolicies::PolicyID /*unused*/)
{
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 314f27dc5..b70511980 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -261,7 +261,25 @@ class cmMakefile;
3, 14, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0088, \
"FindBISON runs bison in CMAKE_CURRENT_BINARY_DIR when executing.", \
- 3, 14, 0, cmPolicies::WARN)
+ 3, 14, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0089, \
+ "Compiler id for IBM Clang-based XL compilers is now XLClang.", 3, \
+ 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0090, \
+ "export(PACKAGE) does not populate package registry by default.", 3, \
+ 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0091, \
+ "MSVC runtime library flags are selected by an abstraction.", 3, 15, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0092, \
+ "MSVC warning flags are not in CMAKE_<LANG>_FLAGS by default.", 3, \
+ 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0093, "FindBoost reports Boost_VERSION in x.y.z format.", \
+ 3, 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0094, \
+ "FindPython3, FindPython2 and FindPyton use " \
+ "LOCATION for lookup strategy.", \
+ 3, 15, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
@@ -326,27 +344,27 @@ public:
CMPCOUNT
};
- ///! convert a string policy ID into a number
+ //! convert a string policy ID into a number
static bool GetPolicyID(const char* id, /* out */ cmPolicies::PolicyID& pid);
- ///! Get the default status for a policy
+ //! Get the default status for a policy
static cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id);
- ///! Set a policy level for this listfile
+ //! Set a policy level for this listfile
static bool ApplyPolicyVersion(cmMakefile* mf,
std::string const& version_min,
std::string const& version_max);
static bool ApplyPolicyVersion(cmMakefile* mf, unsigned int majorVer,
unsigned int minorVer, unsigned int patchVer);
- ///! return a warning string for a given policy
+ //! return a warning string for a given policy
static std::string GetPolicyWarning(cmPolicies::PolicyID id);
static std::string GetPolicyDeprecatedWarning(cmPolicies::PolicyID id);
- ///! return an error string for when a required policy is unspecified
+ //! return an error string for when a required policy is unspecified
static std::string GetRequiredPolicyError(cmPolicies::PolicyID id);
- ///! return an error string for when a required policy is unspecified
+ //! return an error string for when a required policy is unspecified
static std::string GetRequiredAlwaysPolicyError(cmPolicies::PolicyID id);
/** Represent a set of policy values. */
diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx
index 2fe9fe8b9..8615ecc8d 100644
--- a/Source/cmProjectCommand.cxx
+++ b/Source/cmProjectCommand.cxx
@@ -25,6 +25,10 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args,
return false;
}
+ if (!this->IncludeByVariable("CMAKE_PROJECT_INCLUDE_BEFORE")) {
+ return false;
+ }
+
std::string const& projectName = args[0];
this->Makefile->SetProjectName(projectName);
@@ -214,7 +218,7 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args,
}
cmsys::RegularExpression vx(
- "^([0-9]+(\\.[0-9]+(\\.[0-9]+(\\.[0-9]+)?)?)?)?$");
+ R"(^([0-9]+(\.[0-9]+(\.[0-9]+(\.[0-9]+)?)?)?)?$)");
if (!vx.find(version)) {
std::string e = "VERSION \"" + version + "\" format invalid.";
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
@@ -319,21 +323,41 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args,
languages.emplace_back("CXX");
}
this->Makefile->EnableLanguage(languages, false);
- std::string extraInclude = "CMAKE_PROJECT_" + projectName + "_INCLUDE";
- const char* include = this->Makefile->GetDefinition(extraInclude);
- if (include) {
- bool readit = this->Makefile->ReadDependentFile(include);
- if (!readit && !cmSystemTools::GetFatalErrorOccured()) {
- std::string m = "could not find file:\n"
- " ";
- m += include;
- this->SetError(m);
- return false;
- }
+
+ if (!this->IncludeByVariable("CMAKE_PROJECT_INCLUDE")) {
+ return false;
}
+
+ if (!this->IncludeByVariable("CMAKE_PROJECT_" + projectName + "_INCLUDE")) {
+ return false;
+ }
+
return true;
}
+bool cmProjectCommand::IncludeByVariable(const std::string& variable)
+{
+ const char* include = this->Makefile->GetDefinition(variable);
+ if (!include) {
+ return true;
+ }
+
+ const bool readit = this->Makefile->ReadDependentFile(include);
+ if (readit) {
+ return true;
+ }
+
+ if (cmSystemTools::GetFatalErrorOccured()) {
+ return true;
+ }
+
+ std::string m = "could not find file:\n"
+ " ";
+ m += include;
+ this->SetError(m);
+ return false;
+}
+
void cmProjectCommand::TopLevelCMakeVarCondSet(const char* const name,
const char* const value)
{
diff --git a/Source/cmProjectCommand.h b/Source/cmProjectCommand.h
index 365d4487a..f1d03e71d 100644
--- a/Source/cmProjectCommand.h
+++ b/Source/cmProjectCommand.h
@@ -36,6 +36,7 @@ public:
cmExecutionStatus& status) override;
private:
+ bool IncludeByVariable(const std::string& variable);
void TopLevelCMakeVarCondSet(const char* name, const char* value);
};
diff --git a/Source/cmQTWrapCPPCommand.cxx b/Source/cmQTWrapCPPCommand.cxx
index 6acc7ef86..9a764c678 100644
--- a/Source/cmQTWrapCPPCommand.cxx
+++ b/Source/cmQTWrapCPPCommand.cxx
@@ -4,6 +4,7 @@
#include "cmCustomCommandLines.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmSystemTools.h"
@@ -29,13 +30,13 @@ bool cmQTWrapCPPCommand::InitialPass(std::vector<std::string> const& args,
std::string sourceListValue = this->Makefile->GetSafeDefinition(sourceList);
// Create a rule for all sources listed.
- for (std::vector<std::string>::const_iterator j = (args.begin() + 2);
- j != args.end(); ++j) {
- cmSourceFile* curr = this->Makefile->GetSource(*j);
+ for (std::string const& arg : cmMakeRange(args).advance(2)) {
+ cmSourceFile* curr = this->Makefile->GetSource(arg);
// if we should wrap the class
if (!(curr && curr->GetPropertyAsBool("WRAP_EXCLUDE"))) {
// Compute the name of the file to generate.
- std::string srcName = cmSystemTools::GetFilenameWithoutLastExtension(*j);
+ std::string srcName =
+ cmSystemTools::GetFilenameWithoutLastExtension(arg);
std::string newName = this->Makefile->GetCurrentBinaryDirectory();
newName += "/moc_";
newName += srcName;
@@ -47,8 +48,8 @@ bool cmQTWrapCPPCommand::InitialPass(std::vector<std::string> const& args,
// Compute the name of the header from which to generate the file.
std::string hname;
- if (cmSystemTools::FileIsFullPath(*j)) {
- hname = *j;
+ if (cmSystemTools::FileIsFullPath(arg)) {
+ hname = arg;
} else {
if (curr && curr->GetIsGenerated()) {
hname = this->Makefile->GetCurrentBinaryDirectory();
@@ -56,7 +57,7 @@ bool cmQTWrapCPPCommand::InitialPass(std::vector<std::string> const& args,
hname = this->Makefile->GetCurrentSourceDirectory();
}
hname += "/";
- hname += *j;
+ hname += arg;
}
// Append the generated source file to the list.
diff --git a/Source/cmQTWrapUICommand.cxx b/Source/cmQTWrapUICommand.cxx
index 43b1fb9b6..2223e2d82 100644
--- a/Source/cmQTWrapUICommand.cxx
+++ b/Source/cmQTWrapUICommand.cxx
@@ -4,6 +4,7 @@
#include "cmCustomCommandLines.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmSystemTools.h"
@@ -33,13 +34,13 @@ bool cmQTWrapUICommand::InitialPass(std::vector<std::string> const& args,
std::string sourceListValue = this->Makefile->GetSafeDefinition(sourceList);
// Create rules for all sources listed.
- for (std::vector<std::string>::const_iterator j = (args.begin() + 3);
- j != args.end(); ++j) {
- cmSourceFile* curr = this->Makefile->GetSource(*j);
+ for (std::string const& arg : cmMakeRange(args).advance(3)) {
+ cmSourceFile* curr = this->Makefile->GetSource(arg);
// if we should wrap the class
if (!(curr && curr->GetPropertyAsBool("WRAP_EXCLUDE"))) {
// Compute the name of the files to generate.
- std::string srcName = cmSystemTools::GetFilenameWithoutLastExtension(*j);
+ std::string srcName =
+ cmSystemTools::GetFilenameWithoutLastExtension(arg);
std::string hName = this->Makefile->GetCurrentBinaryDirectory();
hName += "/";
hName += srcName;
@@ -55,8 +56,8 @@ bool cmQTWrapUICommand::InitialPass(std::vector<std::string> const& args,
// Compute the name of the ui file from which to generate others.
std::string uiName;
- if (cmSystemTools::FileIsFullPath(*j)) {
- uiName = *j;
+ if (cmSystemTools::FileIsFullPath(arg)) {
+ uiName = arg;
} else {
if (curr && curr->GetIsGenerated()) {
uiName = this->Makefile->GetCurrentBinaryDirectory();
@@ -64,7 +65,7 @@ bool cmQTWrapUICommand::InitialPass(std::vector<std::string> const& args,
uiName = this->Makefile->GetCurrentSourceDirectory();
}
uiName += "/";
- uiName += *j;
+ uiName += arg;
}
// create the list of headers
diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx
index 653caf75b..3683eddda 100644
--- a/Source/cmQtAutoGen.cxx
+++ b/Source/cmQtAutoGen.cxx
@@ -1,23 +1,19 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmQtAutoGen.h"
+
#include "cmAlgorithms.h"
+#include "cmDuration.h"
+#include "cmProcessOutput.h"
#include "cmSystemTools.h"
-
+#include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
#include <algorithm>
-#include <iterator>
+#include <array>
#include <sstream>
#include <utility>
-// - Static variables
-
-std::string const genNameGen = "AutoGen";
-std::string const genNameMoc = "AutoMoc";
-std::string const genNameUic = "AutoUic";
-std::string const genNameRcc = "AutoRcc";
-
// - Static functions
/// @brief Merges newOpts into baseOpts
@@ -72,32 +68,52 @@ void MergeOptions(std::vector<std::string>& baseOpts,
}
}
// Append options
- baseOpts.insert(baseOpts.end(), extraOpts.begin(), extraOpts.end());
+ cmAppend(baseOpts, extraOpts);
}
// - Class definitions
-std::string const cmQtAutoGen::ListSep = "<<<S>>>";
unsigned int const cmQtAutoGen::ParallelMax = 64;
+std::string const cmQtAutoGen::ListSep = "<<<S>>>";
-std::string const& cmQtAutoGen::GeneratorName(GeneratorT type)
+std::string const& cmQtAutoGen::GeneratorName(GenT genType)
{
- switch (type) {
- case GeneratorT::GEN:
- return genNameGen;
- case GeneratorT::MOC:
- return genNameMoc;
- case GeneratorT::UIC:
- return genNameUic;
- case GeneratorT::RCC:
- return genNameRcc;
+ static const std::string AutoGen("AutoGen");
+ static const std::string AutoMoc("AutoMoc");
+ static const std::string AutoUic("AutoUic");
+ static const std::string AutoRcc("AutoRcc");
+
+ switch (genType) {
+ case GenT::GEN:
+ return AutoGen;
+ case GenT::MOC:
+ return AutoMoc;
+ case GenT::UIC:
+ return AutoUic;
+ case GenT::RCC:
+ return AutoRcc;
}
- return genNameGen;
+ return AutoGen;
}
-std::string cmQtAutoGen::GeneratorNameUpper(GeneratorT genType)
+std::string const& cmQtAutoGen::GeneratorNameUpper(GenT genType)
{
- return cmSystemTools::UpperCase(cmQtAutoGen::GeneratorName(genType));
+ static const std::string AUTOGEN("AUTOGEN");
+ static const std::string AUTOMOC("AUTOMOC");
+ static const std::string AUTOUIC("AUTOUIC");
+ static const std::string AUTORCC("AUTORCC");
+
+ switch (genType) {
+ case GenT::GEN:
+ return AUTOGEN;
+ case GenT::MOC:
+ return AUTOMOC;
+ case GenT::UIC:
+ return AUTOUIC;
+ case GenT::RCC:
+ return AUTORCC;
+ }
+ return AUTOGEN;
}
std::string cmQtAutoGen::Tools(bool moc, bool uic, bool rcc)
@@ -137,13 +153,21 @@ std::string cmQtAutoGen::Tools(bool moc, bool uic, bool rcc)
std::string cmQtAutoGen::Quoted(std::string const& text)
{
- static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a",
- "\b", "\\b", "\f", "\\f", "\n", "\\n",
- "\r", "\\r", "\t", "\\t", "\v", "\\v" };
+ const std::array<std::pair<const char*, const char*>, 9> replaces = {
+ { { "\\", "\\\\" },
+ { "\"", "\\\"" },
+ { "\a", "\\a" },
+ { "\b", "\\b" },
+ { "\f", "\\f" },
+ { "\n", "\\n" },
+ { "\r", "\\r" },
+ { "\t", "\\t" },
+ { "\v", "\\v" } }
+ };
std::string res = text;
- for (const char* const* it = cm::cbegin(rep); it != cm::cend(rep); it += 2) {
- cmSystemTools::ReplaceString(res, *it, *(it + 1));
+ for (auto const& pair : replaces) {
+ cmSystemTools::ReplaceString(res, pair.first, pair.second);
}
res = '"' + res;
res += '"';
@@ -170,11 +194,11 @@ std::string cmQtAutoGen::QuotedCommand(std::vector<std::string> const& command)
std::string cmQtAutoGen::SubDirPrefix(std::string const& filename)
{
- std::string res(cmSystemTools::GetFilenamePath(filename));
- if (!res.empty()) {
- res += '/';
+ std::string::size_type slash_pos = filename.rfind('/');
+ if (slash_pos == std::string::npos) {
+ return std::string();
}
- return res;
+ return filename.substr(0, slash_pos + 1);
}
std::string cmQtAutoGen::AppendFilenameSuffix(std::string const& filename,
@@ -216,8 +240,8 @@ void cmQtAutoGen::RccMergeOptions(std::vector<std::string>& baseOpts,
MergeOptions(baseOpts, newOpts, valueOpts, isQt5);
}
-void cmQtAutoGen::RccListParseContent(std::string const& content,
- std::vector<std::string>& files)
+static void RccListParseContent(std::string const& content,
+ std::vector<std::string>& files)
{
cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)");
@@ -234,10 +258,10 @@ void cmQtAutoGen::RccListParseContent(std::string const& content,
}
}
-bool cmQtAutoGen::RccListParseOutput(std::string const& rccStdOut,
- std::string const& rccStdErr,
- std::vector<std::string>& files,
- std::string& error)
+static bool RccListParseOutput(std::string const& rccStdOut,
+ std::string const& rccStdErr,
+ std::vector<std::string>& files,
+ std::string& error)
{
// Lambda to strip CR characters
auto StripCR = [](std::string& line) {
@@ -284,11 +308,103 @@ bool cmQtAutoGen::RccListParseOutput(std::string const& rccStdOut,
return true;
}
-void cmQtAutoGen::RccListConvertFullPath(std::string const& qrcFileDir,
- std::vector<std::string>& files)
+cmQtAutoGen::RccLister::RccLister() = default;
+
+cmQtAutoGen::RccLister::RccLister(std::string rccExecutable,
+ std::vector<std::string> listOptions)
+ : RccExcutable_(std::move(rccExecutable))
+ , ListOptions_(std::move(listOptions))
+{
+}
+
+bool cmQtAutoGen::RccLister::list(std::string const& qrcFile,
+ std::vector<std::string>& files,
+ std::string& error, bool verbose) const
{
+ error.clear();
+
+ if (!cmSystemTools::FileExists(qrcFile, true)) {
+ error = "The resource file ";
+ error += Quoted(qrcFile);
+ error += " does not exist.";
+ return false;
+ }
+
+ // Run rcc list command in the directory of the qrc file with the pathless
+ // qrc file name argument. This way rcc prints relative paths.
+ // This avoids issues on Windows when the qrc file is in a path that
+ // contains non-ASCII characters.
+ std::string const fileDir = cmSystemTools::GetFilenamePath(qrcFile);
+
+ if (!this->RccExcutable_.empty() &&
+ cmSystemTools::FileExists(this->RccExcutable_, true) &&
+ !this->ListOptions_.empty()) {
+
+ bool result = false;
+ int retVal = 0;
+ std::string rccStdOut;
+ std::string rccStdErr;
+ {
+ std::vector<std::string> cmd;
+ cmd.emplace_back(this->RccExcutable_);
+ cmAppend(cmd, this->ListOptions_);
+ cmd.emplace_back(cmSystemTools::GetFilenameName(qrcFile));
+
+ // Log command
+ if (verbose) {
+ std::string msg = "Running command:\n";
+ msg += QuotedCommand(cmd);
+ msg += '\n';
+ cmSystemTools::Stdout(msg);
+ }
+
+ result = cmSystemTools::RunSingleCommand(
+ cmd, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(),
+ cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto);
+ }
+ if (!result || retVal) {
+ error = "The rcc list process failed for ";
+ error += Quoted(qrcFile);
+ error += "\n";
+ if (!rccStdOut.empty()) {
+ error += rccStdOut;
+ error += "\n";
+ }
+ if (!rccStdErr.empty()) {
+ error += rccStdErr;
+ error += "\n";
+ }
+ return false;
+ }
+ if (!RccListParseOutput(rccStdOut, rccStdErr, files, error)) {
+ return false;
+ }
+ } else {
+ // We can't use rcc for the file listing.
+ // Read the qrc file content into string and parse it.
+ {
+ std::string qrcContents;
+ {
+ cmsys::ifstream ifs(qrcFile.c_str());
+ if (ifs) {
+ std::ostringstream osst;
+ osst << ifs.rdbuf();
+ qrcContents = osst.str();
+ } else {
+ error = "The resource file ";
+ error += Quoted(qrcFile);
+ error += " is not readable\n";
+ return false;
+ }
+ }
+ // Parse string content
+ RccListParseContent(qrcContents, files);
+ }
+ }
+
+ // Convert relative paths to absolute paths
for (std::string& entry : files) {
- std::string tmp = cmSystemTools::CollapseCombinedPath(qrcFileDir, entry);
- entry = std::move(tmp);
+ entry = cmSystemTools::CollapseFullPath(entry, fileDir);
}
+ return true;
}
diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h
index 96d1946f0..9c5212952 100644
--- a/Source/cmQtAutoGen.h
+++ b/Source/cmQtAutoGen.h
@@ -5,6 +5,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <memory> // IWYU pragma: keep
#include <string>
#include <vector>
@@ -14,20 +15,6 @@
class cmQtAutoGen
{
public:
- /// @brief Nested lists separator
- static std::string const ListSep;
- /// @brief Maximum number of parallel threads/processes in a generator
- static unsigned int const ParallelMax;
-
- /// @brief AutoGen generator type
- enum class GeneratorT
- {
- GEN, // General
- MOC,
- UIC,
- RCC
- };
-
/// @brief Integer version
struct IntegerVersion
{
@@ -54,11 +41,34 @@ public:
}
};
+ class CompilerFeatures
+ {
+ public:
+ bool Evaluated = false;
+ std::string HelpOutput;
+ std::vector<std::string> ListOptions;
+ };
+ typedef std::shared_ptr<CompilerFeatures> CompilerFeaturesHandle;
+
+ /// @brief AutoGen generator type
+ enum class GenT
+ {
+ GEN, // AUTOGEN
+ MOC, // AUTOMOC
+ UIC, // AUTOUIC
+ RCC // AUTORCC
+ };
+
+ /// @brief Nested lists separator
+ static std::string const ListSep;
+ /// @brief Maximum number of parallel threads/processes in a generator
+ static unsigned int const ParallelMax;
+
public:
/// @brief Returns the generator name
- static std::string const& GeneratorName(GeneratorT genType);
+ static std::string const& GeneratorName(GenT genType);
/// @brief Returns the generator name in upper case
- static std::string GeneratorNameUpper(GeneratorT genType);
+ static std::string const& GeneratorNameUpper(GenT genType);
/// @brief Returns a string with the requested tool names
static std::string Tools(bool moc, bool uic, bool rcc);
@@ -85,21 +95,44 @@ public:
std::vector<std::string> const& newOpts,
bool isQt5);
- /// @brief Parses the content of a qrc file
- ///
- /// Use when rcc does not support the "--list" option
- static void RccListParseContent(std::string const& content,
- std::vector<std::string>& files);
-
- /// @brief Parses the output of the "rcc --list ..." command
- static bool RccListParseOutput(std::string const& rccStdOut,
- std::string const& rccStdErr,
- std::vector<std::string>& files,
- std::string& error);
-
- /// @brief Converts relative qrc entry paths to full paths
- static void RccListConvertFullPath(std::string const& qrcFileDir,
- std::vector<std::string>& files);
+ /** @class RccLister
+ * @brief Lists files in qrc resource files
+ */
+ class RccLister
+ {
+ public:
+ RccLister();
+ RccLister(std::string rccExecutable, std::vector<std::string> listOptions);
+
+ //! The rcc executable
+ std::string const& RccExcutable() const { return RccExcutable_; }
+ void SetRccExecutable(std::string const& rccExecutable)
+ {
+ RccExcutable_ = rccExecutable;
+ }
+
+ //! The rcc executable list options
+ std::vector<std::string> const& ListOptions() const
+ {
+ return ListOptions_;
+ }
+ void SetListOptions(std::vector<std::string> const& listOptions)
+ {
+ ListOptions_ = listOptions;
+ }
+
+ /**
+ * @brief Lists a files in the qrcFile
+ * @arg files The file names are appended to this list
+ * @arg error contains the error message when the function fails
+ */
+ bool list(std::string const& qrcFile, std::vector<std::string>& files,
+ std::string& error, bool verbose = false) const;
+
+ private:
+ std::string RccExcutable_;
+ std::vector<std::string> ListOptions_;
+ };
};
#endif
diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx
index 3ad91eec6..ef8a56b3b 100644
--- a/Source/cmQtAutoGenGlobalInitializer.cxx
+++ b/Source/cmQtAutoGenGlobalInitializer.cxx
@@ -20,6 +20,24 @@
#include <memory>
#include <utility>
+cmQtAutoGenGlobalInitializer::Keywords::Keywords()
+ : AUTOMOC("AUTOMOC")
+ , AUTOUIC("AUTOUIC")
+ , AUTORCC("AUTORCC")
+ , AUTOMOC_EXECUTABLE("AUTOMOC_EXECUTABLE")
+ , AUTOUIC_EXECUTABLE("AUTOUIC_EXECUTABLE")
+ , AUTORCC_EXECUTABLE("AUTORCC_EXECUTABLE")
+ , SKIP_AUTOGEN("SKIP_AUTOGEN")
+ , SKIP_AUTOMOC("SKIP_AUTOMOC")
+ , SKIP_AUTOUIC("SKIP_AUTOUIC")
+ , SKIP_AUTORCC("SKIP_AUTORCC")
+ , AUTOUIC_OPTIONS("AUTOUIC_OPTIONS")
+ , AUTORCC_OPTIONS("AUTORCC_OPTIONS")
+ , qrc("qrc")
+ , ui("ui")
+{
+}
+
cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
std::vector<cmLocalGenerator*> const& localGenerators)
{
@@ -74,16 +92,16 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
continue;
}
- bool const moc = target->GetPropertyAsBool("AUTOMOC");
- bool const uic = target->GetPropertyAsBool("AUTOUIC");
- bool const rcc = target->GetPropertyAsBool("AUTORCC");
+ bool const moc = target->GetPropertyAsBool(kw().AUTOMOC);
+ bool const uic = target->GetPropertyAsBool(kw().AUTOUIC);
+ bool const rcc = target->GetPropertyAsBool(kw().AUTORCC);
if (moc || uic || rcc) {
std::string const mocExec =
- target->GetSafeProperty("AUTOMOC_EXECUTABLE");
+ target->GetSafeProperty(kw().AUTOMOC_EXECUTABLE);
std::string const uicExec =
- target->GetSafeProperty("AUTOUIC_EXECUTABLE");
+ target->GetSafeProperty(kw().AUTOUIC_EXECUTABLE);
std::string const rccExec =
- target->GetSafeProperty("AUTORCC_EXECUTABLE");
+ target->GetSafeProperty(kw().AUTORCC_EXECUTABLE);
// We support Qt4, Qt5 and Qt6
auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target);
@@ -185,19 +203,16 @@ void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc(
}
}
-bool cmQtAutoGenGlobalInitializer::GetExecutableTestOutput(
+cmQtAutoGen::CompilerFeaturesHandle
+cmQtAutoGenGlobalInitializer::GetCompilerFeatures(
std::string const& generator, std::string const& executable,
- std::string& error, std::string* output)
+ std::string& error)
{
- // Check if we have cached output
+ // Check if we have cached features
{
- auto it = this->ExecutableTestOutputs_.find(executable);
- if (it != this->ExecutableTestOutputs_.end()) {
- // Return output on demand
- if (output != nullptr) {
- *output = it->second;
- }
- return true;
+ auto it = this->CompilerFeatures_.find(executable);
+ if (it != this->CompilerFeatures_.end()) {
+ return it->second;
}
}
@@ -208,7 +223,7 @@ bool cmQtAutoGenGlobalInitializer::GetExecutableTestOutput(
error += "\" executable ";
error += cmQtAutoGen::Quoted(executable);
error += " does not exist.";
- return false;
+ return cmQtAutoGen::CompilerFeaturesHandle();
}
// Test the executable
@@ -216,7 +231,7 @@ bool cmQtAutoGenGlobalInitializer::GetExecutableTestOutput(
{
std::string stdErr;
std::vector<std::string> command;
- command.push_back(executable);
+ command.emplace_back(executable);
command.emplace_back("-h");
int retVal = 0;
const bool runResult = cmSystemTools::RunSingleCommand(
@@ -232,19 +247,19 @@ bool cmQtAutoGenGlobalInitializer::GetExecutableTestOutput(
error += stdOut;
error += "\n";
error += stdErr;
- return false;
+ return cmQtAutoGen::CompilerFeaturesHandle();
}
}
- // Return executable output on demand
- if (output != nullptr) {
- *output = stdOut;
- }
+ // Create valid handle
+ cmQtAutoGen::CompilerFeaturesHandle res =
+ std::make_shared<cmQtAutoGen::CompilerFeatures>();
+ res->HelpOutput = std::move(stdOut);
- // Register executable and output
- this->ExecutableTestOutputs_.emplace(executable, std::move(stdOut));
+ // Register compiler features
+ this->CompilerFeatures_.emplace(executable, res);
- return true;
+ return res;
}
bool cmQtAutoGenGlobalInitializer::generate()
diff --git a/Source/cmQtAutoGenGlobalInitializer.h b/Source/cmQtAutoGenGlobalInitializer.h
index 74184a0d5..d56153ab7 100644
--- a/Source/cmQtAutoGenGlobalInitializer.h
+++ b/Source/cmQtAutoGenGlobalInitializer.h
@@ -5,6 +5,8 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cmQtAutoGen.h"
+
#include <map>
#include <memory> // IWYU pragma: keep
#include <string>
@@ -18,10 +20,39 @@ class cmQtAutoGenInitializer;
class cmQtAutoGenGlobalInitializer
{
public:
+ /// @brief Collection of QtAutogen related keywords
+ class Keywords
+ {
+ public:
+ Keywords();
+
+ std::string AUTOMOC;
+ std::string AUTOUIC;
+ std::string AUTORCC;
+
+ std::string AUTOMOC_EXECUTABLE;
+ std::string AUTOUIC_EXECUTABLE;
+ std::string AUTORCC_EXECUTABLE;
+
+ std::string SKIP_AUTOGEN;
+ std::string SKIP_AUTOMOC;
+ std::string SKIP_AUTOUIC;
+ std::string SKIP_AUTORCC;
+
+ std::string AUTOUIC_OPTIONS;
+ std::string AUTORCC_OPTIONS;
+
+ std::string qrc;
+ std::string ui;
+ };
+
+public:
cmQtAutoGenGlobalInitializer(
std::vector<cmLocalGenerator*> const& localGenerators);
~cmQtAutoGenGlobalInitializer();
+ Keywords const& kw() const { return Keywords_; };
+
bool generate();
private:
@@ -39,15 +70,17 @@ private:
void AddToGlobalAutoRcc(cmLocalGenerator* localGen,
std::string const& targetName);
- bool GetExecutableTestOutput(std::string const& generator,
- std::string const& executable,
- std::string& error, std::string* output);
+ cmQtAutoGen::CompilerFeaturesHandle GetCompilerFeatures(
+ std::string const& generator, std::string const& executable,
+ std::string& error);
private:
std::vector<std::unique_ptr<cmQtAutoGenInitializer>> Initializers_;
std::map<cmLocalGenerator*, std::string> GlobalAutoGenTargets_;
std::map<cmLocalGenerator*, std::string> GlobalAutoRccTargets_;
- std::unordered_map<std::string, std::string> ExecutableTestOutputs_;
+ std::unordered_map<std::string, cmQtAutoGen::CompilerFeaturesHandle>
+ CompilerFeatures_;
+ Keywords const Keywords_;
};
#endif
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 614a88bde..9985f93eb 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -7,7 +7,6 @@
#include "cmAlgorithms.h"
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
-#include "cmDuration.h"
#include "cmFilePathChecksum.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
@@ -19,14 +18,14 @@
#include "cmMessageType.h"
#include "cmOutputConverter.h"
#include "cmPolicies.h"
-#include "cmProcessOutput.h"
#include "cmSourceFile.h"
+#include "cmSourceFileLocationKind.h"
#include "cmSourceGroup.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
-#include "cmsys/FStream.hxx"
+#include "cmake.h"
#include "cmsys/SystemInformation.hxx"
#include <algorithm>
@@ -34,27 +33,11 @@
#include <deque>
#include <map>
#include <set>
-#include <sstream>
#include <string>
-#include <type_traits>
+#include <unordered_set>
#include <utility>
#include <vector>
-std::string GetQtExecutableTargetName(
- const cmQtAutoGen::IntegerVersion& qtVersion, std::string const& executable)
-{
- if (qtVersion.Major == 6) {
- return ("Qt6::" + executable);
- }
- if (qtVersion.Major == 5) {
- return ("Qt5::" + executable);
- }
- if (qtVersion.Major == 4) {
- return ("Qt4::" + executable);
- }
- return ("");
-}
-
static std::size_t GetParallelCPUCount()
{
static std::size_t count = 0;
@@ -69,64 +52,6 @@ static std::size_t GetParallelCPUCount()
return count;
}
-static bool AddToSourceGroup(cmMakefile* makefile, std::string const& fileName,
- cmQtAutoGen::GeneratorT genType)
-{
- cmSourceGroup* sourceGroup = nullptr;
- // Acquire source group
- {
- std::string property;
- std::string groupName;
- {
- std::array<std::string, 2> props;
- // Use generator specific group name
- switch (genType) {
- case cmQtAutoGen::GeneratorT::MOC:
- props[0] = "AUTOMOC_SOURCE_GROUP";
- break;
- case cmQtAutoGen::GeneratorT::RCC:
- props[0] = "AUTORCC_SOURCE_GROUP";
- break;
- default:
- props[0] = "AUTOGEN_SOURCE_GROUP";
- break;
- }
- props[1] = "AUTOGEN_SOURCE_GROUP";
- for (std::string& prop : props) {
- const char* propName = makefile->GetState()->GetGlobalProperty(prop);
- if ((propName != nullptr) && (*propName != '\0')) {
- groupName = propName;
- property = std::move(prop);
- break;
- }
- }
- }
- // Generate a source group on demand
- if (!groupName.empty()) {
- sourceGroup = makefile->GetOrCreateSourceGroup(groupName);
- if (sourceGroup == nullptr) {
- std::ostringstream ost;
- ost << cmQtAutoGen::GeneratorNameUpper(genType);
- ost << ": " << property;
- ost << ": Could not find or create the source group ";
- ost << cmQtAutoGen::Quoted(groupName);
- cmSystemTools::Error(ost.str());
- return false;
- }
- }
- }
- if (sourceGroup != nullptr) {
- sourceGroup->AddGroupFile(fileName);
- }
- return true;
-}
-
-static void AddCleanFile(cmMakefile* makefile, std::string const& fileName)
-{
- makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fileName.c_str(),
- false);
-}
-
static std::string FileProjectRelativePath(cmMakefile* makefile,
std::string const& fileName)
{
@@ -147,7 +72,8 @@ static std::string FileProjectRelativePath(cmMakefile* makefile,
return res;
}
-/* @brief Tests if targetDepend is a STATIC_LIBRARY and if any of its
+/**
+ * Tests if targetDepend is a STATIC_LIBRARY and if any of its
* recursive STATIC_LIBRARY dependencies depends on targetOrigin
* (STATIC_LIBRARY cycle).
*/
@@ -343,6 +269,26 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
}
+ // Check status of policy CMP0071
+ {
+ cmPolicies::PolicyStatus const CMP0071_status =
+ makefile->GetPolicyStatus(cmPolicies::CMP0071);
+ switch (CMP0071_status) {
+ case cmPolicies::WARN:
+ this->CMP0071Warn = true;
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ // Ignore GENERATED file
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Process GENERATED file
+ this->CMP0071Accept = true;
+ break;
+ }
+ }
+
// Common directories
{
// Collapsed current binary directory
@@ -368,7 +314,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
cmSystemTools::ConvertToUnixSlashes(this->Dir.Build);
// Cleanup build directory
- AddCleanFile(makefile, this->Dir.Build);
+ this->AddCleanFile(this->Dir.Build);
// Working directory
this->Dir.Work = cbd;
@@ -392,23 +338,15 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
// Moc, Uic and _autogen target settings
- if (this->Moc.Enabled || this->Uic.Enabled) {
+ if (this->MocOrUicEnabled()) {
// Init moc specific settings
if (this->Moc.Enabled && !InitMoc()) {
return false;
}
// Init uic specific settings
- if (this->Uic.Enabled) {
- if (InitUic()) {
- auto* uicTarget = makefile->FindTargetToUse(
- GetQtExecutableTargetName(this->QtVersion, "uic"));
- if (uicTarget != nullptr) {
- this->AutogenTarget.DependTargets.insert(uicTarget);
- }
- } else {
- return false;
- }
+ if (this->Uic.Enabled && !InitUic()) {
+ return false;
}
// Autogen target name
@@ -437,11 +375,15 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
std::string& filename = this->AutogenTarget.ConfigSettingsFile[cfg];
filename =
AppendFilenameSuffix(this->AutogenTarget.SettingsFile, "_" + cfg);
- AddCleanFile(makefile, filename);
+ this->AddCleanFile(filename);
}
} else {
- AddCleanFile(makefile, this->AutogenTarget.SettingsFile);
+ this->AddCleanFile(this->AutogenTarget.SettingsFile);
}
+
+ this->AutogenTarget.ParseCacheFile = this->Dir.Info;
+ this->AutogenTarget.ParseCacheFile += "/ParseCache.txt";
+ this->AddCleanFile(this->AutogenTarget.ParseCacheFile);
}
// Autogen target: Compute user defined dependencies
@@ -449,12 +391,6 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
this->AutogenTarget.DependOrigin =
this->Target->GetPropertyAsBool("AUTOGEN_ORIGIN_DEPENDS");
- auto* mocTarget = makefile->FindTargetToUse(
- GetQtExecutableTargetName(this->QtVersion, "moc"));
- if (mocTarget != nullptr) {
- this->AutogenTarget.DependTargets.insert(mocTarget);
- }
-
std::string const deps =
this->Target->GetSafeProperty("AUTOGEN_TARGET_DEPENDS");
if (!deps.empty()) {
@@ -471,6 +407,19 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
}
}
+
+ // CMAKE_AUTOMOC_RELAXED_MODE deprecation warning
+ if (this->Moc.Enabled) {
+ if (cmSystemTools::IsOn(
+ makefile->GetDefinition("CMAKE_AUTOMOC_RELAXED_MODE"))) {
+ std::string msg = "AUTOMOC: CMAKE_AUTOMOC_RELAXED_MODE is "
+ "deprecated an will be removed in the future. ";
+ msg += "Consider disabling it and converting the target ";
+ msg += this->Target->GetName();
+ msg += " to regular mode.";
+ makefile->IssueMessage(MessageType::AUTHOR_WARNING, msg);
+ }
+ }
}
// Init rcc specific settings
@@ -479,8 +428,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
// Add autogen include directory to the origin target INCLUDE_DIRECTORIES
- if (this->Moc.Enabled || this->Uic.Enabled ||
- (this->Rcc.Enabled && this->MultiConfig)) {
+ if (this->MocOrUicEnabled() || (this->Rcc.Enabled && this->MultiConfig)) {
this->Target->AddIncludeDirectory(this->Dir.Include, true);
}
@@ -490,7 +438,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
}
// Create autogen target
- if ((this->Moc.Enabled || this->Uic.Enabled) && !this->InitAutogenTarget()) {
+ if (this->MocOrUicEnabled() && !this->InitAutogenTarget()) {
return false;
}
@@ -575,7 +523,18 @@ bool cmQtAutoGenInitializer::InitMoc()
}
// Moc executable
- return GetMocExecutable();
+ {
+ if (!this->GetQtExecutable(this->Moc, "moc", false)) {
+ return false;
+ }
+ // Let the _autogen target depend on the moc executable
+ if (this->Moc.ExecutableTarget != nullptr) {
+ this->AutogenTarget.DependTargets.insert(
+ this->Moc.ExecutableTarget->Target);
+ }
+ }
+
+ return true;
}
bool cmQtAutoGenInitializer::InitUic()
@@ -618,83 +577,123 @@ bool cmQtAutoGenInitializer::InitUic()
}
// Uic executable
- return GetUicExecutable();
+ {
+ if (!this->GetQtExecutable(this->Uic, "uic", true)) {
+ return false;
+ }
+ // Let the _autogen target depend on the uic executable
+ if (this->Uic.ExecutableTarget != nullptr) {
+ this->AutogenTarget.DependTargets.insert(
+ this->Uic.ExecutableTarget->Target);
+ }
+ }
+
+ return true;
}
bool cmQtAutoGenInitializer::InitRcc()
{
- return GetRccExecutable();
+ // Rcc executable
+ {
+ if (!this->GetQtExecutable(this->Rcc, "rcc", false)) {
+ return false;
+ }
+ // Evaluate test output on demand
+ CompilerFeatures& features = *this->Rcc.ExecutableFeatures;
+ if (!features.Evaluated) {
+ // Look for list options
+ if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) {
+ if (features.HelpOutput.find("--list") != std::string::npos) {
+ features.ListOptions.emplace_back("--list");
+ } else if (features.HelpOutput.find("-list") != std::string::npos) {
+ features.ListOptions.emplace_back("-list");
+ }
+ }
+ // Evaluation finished
+ features.Evaluated = true;
+ }
+ }
+
+ return true;
}
bool cmQtAutoGenInitializer::InitScanFiles()
{
cmMakefile* makefile = this->Target->Target->GetMakefile();
+ auto const& kw = this->GlobalInitializer->kw();
+
+ auto makeMUFile = [this, &kw](cmSourceFile* sf, std::string const& fullPath,
+ bool muIt) -> MUFileHandle {
+ MUFileHandle muf = cm::make_unique<MUFile>();
+ muf->RealPath = cmSystemTools::GetRealPath(fullPath);
+ muf->SF = sf;
+ muf->Generated = sf->GetIsGenerated();
+ bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN);
+ muf->SkipMoc = this->Moc.Enabled &&
+ (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOMOC));
+ muf->SkipUic = this->Uic.Enabled &&
+ (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC));
+ if (muIt) {
+ muf->MocIt = this->Moc.Enabled && !muf->SkipMoc;
+ muf->UicIt = this->Uic.Enabled && !muf->SkipUic;
+ }
+ return muf;
+ };
- // String constants
- std::string const SKIP_AUTOGEN_str = "SKIP_AUTOGEN";
- std::string const SKIP_AUTOMOC_str = "SKIP_AUTOMOC";
- std::string const SKIP_AUTOUIC_str = "SKIP_AUTOUIC";
+ auto addMUFile = [&](MUFileHandle&& muf, bool isHeader) {
+ if ((muf->MocIt || muf->UicIt) && muf->Generated) {
+ this->AutogenTarget.FilesGenerated.emplace_back(muf.get());
+ }
+ if (isHeader) {
+ this->AutogenTarget.Headers.emplace(muf->SF, std::move(muf));
+ } else {
+ this->AutogenTarget.Sources.emplace(muf->SF, std::move(muf));
+ }
+ };
// Scan through target files
{
- // String constants
- std::string const qrc_str = "qrc";
- std::string const SKIP_AUTORCC_str = "SKIP_AUTORCC";
- std::string const AUTORCC_OPTIONS_str = "AUTORCC_OPTIONS";
-
// Scan through target files
std::vector<cmSourceFile*> srcFiles;
this->Target->GetConfigCommonSourceFiles(srcFiles);
for (cmSourceFile* sf : srcFiles) {
- if (sf->GetPropertyAsBool(SKIP_AUTOGEN_str)) {
+ // sf->GetExtension() is only valid after sf->GetFullPath() ...
+ // Since we're iterating over source files that might be not in the
+ // target we need to check for path errors (not existing files).
+ std::string pathError;
+ std::string const& fullPath = sf->GetFullPath(&pathError);
+ if (!pathError.empty() || fullPath.empty()) {
continue;
}
-
- // sf->GetExtension() is only valid after sf->GetFullPath() ...
- std::string const& fPath = sf->GetFullPath();
std::string const& ext = sf->GetExtension();
- // Register generated files that will be scanned by moc or uic
- if (this->Moc.Enabled || this->Uic.Enabled) {
- cmSystemTools::FileFormat const fileType =
- cmSystemTools::GetFileFormat(ext);
- if ((fileType == cmSystemTools::CXX_FILE_FORMAT) ||
- (fileType == cmSystemTools::HEADER_FILE_FORMAT)) {
- std::string const absPath = cmSystemTools::GetRealPath(fPath);
- if ((this->Moc.Enabled &&
- !sf->GetPropertyAsBool(SKIP_AUTOMOC_str)) ||
- (this->Uic.Enabled &&
- !sf->GetPropertyAsBool(SKIP_AUTOUIC_str))) {
- // Register source
- const bool generated = sf->GetIsGenerated();
- if (fileType == cmSystemTools::HEADER_FILE_FORMAT) {
- if (generated) {
- this->AutogenTarget.HeadersGenerated.push_back(absPath);
- } else {
- this->AutogenTarget.Headers.push_back(absPath);
- }
- } else {
- if (generated) {
- this->AutogenTarget.SourcesGenerated.push_back(absPath);
- } else {
- this->AutogenTarget.Sources.push_back(absPath);
- }
- }
- }
+ // Register files that will be scanned by moc or uic
+ if (this->MocOrUicEnabled()) {
+ switch (cmSystemTools::GetFileFormat(ext)) {
+ case cmSystemTools::HEADER_FILE_FORMAT:
+ addMUFile(makeMUFile(sf, fullPath, true), true);
+ break;
+ case cmSystemTools::CXX_FILE_FORMAT:
+ addMUFile(makeMUFile(sf, fullPath, true), false);
+ break;
+ default:
+ break;
}
}
+
// Register rcc enabled files
if (this->Rcc.Enabled) {
- if ((ext == qrc_str) && !sf->GetPropertyAsBool(SKIP_AUTORCC_str)) {
+ if ((ext == kw.qrc) && !sf->GetPropertyAsBool(kw.SKIP_AUTOGEN) &&
+ !sf->GetPropertyAsBool(kw.SKIP_AUTORCC)) {
// Register qrc file
Qrc qrc;
- qrc.QrcFile = cmSystemTools::GetRealPath(fPath);
+ qrc.QrcFile = cmSystemTools::GetRealPath(fullPath);
qrc.QrcName =
cmSystemTools::GetFilenameWithoutLastExtension(qrc.QrcFile);
qrc.Generated = sf->GetIsGenerated();
// RCC options
{
- std::string const opts = sf->GetSafeProperty(AUTORCC_OPTIONS_str);
+ std::string const opts = sf->GetSafeProperty(kw.AUTORCC_OPTIONS);
if (!opts.empty()) {
cmSystemTools::ExpandListArgument(opts, qrc.Options);
}
@@ -710,15 +709,72 @@ bool cmQtAutoGenInitializer::InitScanFiles()
// mocs_compilation.cpp source acknowledged by this target.
this->Target->ClearSourcesCache();
+ // For source files find additional headers and private headers
+ if (this->MocOrUicEnabled()) {
+ std::vector<MUFileHandle> extraHeaders;
+ extraHeaders.reserve(this->AutogenTarget.Sources.size() * 2);
+ // Header search suffixes and extensions
+ std::array<std::string, 2> const suffixes{ { "", "_p" } };
+ auto const& exts = makefile->GetCMakeInstance()->GetHeaderExtensions();
+ // Scan through sources
+ for (auto const& pair : this->AutogenTarget.Sources) {
+ MUFile const& muf = *pair.second;
+ if (muf.MocIt || muf.UicIt) {
+ // Search for the default header file and a private header
+ std::string const& srcPath = muf.SF->GetFullPath();
+ std::string basePath = cmQtAutoGen::SubDirPrefix(srcPath);
+ basePath += cmSystemTools::GetFilenameWithoutLastExtension(srcPath);
+ for (auto const& suffix : suffixes) {
+ std::string const suffixedPath = basePath + suffix;
+ for (auto const& ext : exts) {
+ std::string fullPath = suffixedPath;
+ fullPath += '.';
+ fullPath += ext;
+
+ auto constexpr locationKind = cmSourceFileLocationKind::Known;
+ cmSourceFile* sf = makefile->GetSource(fullPath, locationKind);
+ if (sf != nullptr) {
+ // Check if we know about this header already
+ if (this->AutogenTarget.Headers.find(sf) !=
+ this->AutogenTarget.Headers.end()) {
+ continue;
+ }
+ // We only accept not-GENERATED files that do exist.
+ if (!sf->GetIsGenerated() &&
+ !cmSystemTools::FileExists(fullPath)) {
+ continue;
+ }
+ } else if (cmSystemTools::FileExists(fullPath)) {
+ // Create a new source file for the existing file
+ sf = makefile->CreateSource(fullPath, false, locationKind);
+ }
+
+ if (sf != nullptr) {
+ auto eMuf = makeMUFile(sf, fullPath, true);
+ // Ony process moc/uic when the parent is processed as well
+ if (!muf.MocIt) {
+ eMuf->MocIt = false;
+ }
+ if (!muf.UicIt) {
+ eMuf->UicIt = false;
+ }
+ extraHeaders.emplace_back(std::move(eMuf));
+ }
+ }
+ }
+ }
+ }
+ // Move generated files to main headers list
+ for (auto& eMuf : extraHeaders) {
+ addMUFile(std::move(eMuf), true);
+ }
+ }
+
// Scan through all source files in the makefile to extract moc and uic
// parameters. Historically we support non target source file parameters.
// The reason is that their file names might be discovered from source files
// at generation time.
- if (this->Moc.Enabled || this->Uic.Enabled) {
- // String constants
- std::string const ui_str = "ui";
- std::string const AUTOUIC_OPTIONS_str = "AUTOUIC_OPTIONS";
-
+ if (this->MocOrUicEnabled()) {
for (cmSourceFile* sf : makefile->GetSourceFiles()) {
// sf->GetExtension() is only valid after sf->GetFullPath() ...
// Since we're iterating over source files that might be not in the
@@ -728,139 +784,94 @@ bool cmQtAutoGenInitializer::InitScanFiles()
if (!pathError.empty() || fullPath.empty()) {
continue;
}
+ std::string const& ext = sf->GetExtension();
- // Check file type
- auto const fileType = cmSystemTools::GetFileFormat(sf->GetExtension());
- bool const isSource = (fileType == cmSystemTools::CXX_FILE_FORMAT) ||
- (fileType == cmSystemTools::HEADER_FILE_FORMAT);
- bool const isUi = (this->Moc.Enabled && sf->GetExtension() == ui_str);
-
- // Process only certain file types
- if (isSource || isUi) {
- std::string const absFile = cmSystemTools::GetRealPath(fullPath);
- // Acquire file properties
- bool const skipAUTOGEN = sf->GetPropertyAsBool(SKIP_AUTOGEN_str);
- bool const skipMoc = (this->Moc.Enabled && isSource) &&
- (skipAUTOGEN || sf->GetPropertyAsBool(SKIP_AUTOMOC_str));
- bool const skipUic = this->Uic.Enabled &&
- (skipAUTOGEN || sf->GetPropertyAsBool(SKIP_AUTOUIC_str));
-
- // Register moc and uic skipped file
- if (skipMoc) {
- this->Moc.Skip.insert(absFile);
+ auto const fileFormat = cmSystemTools::GetFileFormat(ext);
+ if (fileFormat == cmSystemTools::HEADER_FILE_FORMAT) {
+ if (this->AutogenTarget.Headers.find(sf) ==
+ this->AutogenTarget.Headers.end()) {
+ auto muf = makeMUFile(sf, fullPath, false);
+ if (muf->SkipMoc || muf->SkipUic) {
+ this->AutogenTarget.Headers.emplace(sf, std::move(muf));
+ }
}
- if (skipUic) {
- this->Uic.Skip.insert(absFile);
+ } else if (fileFormat == cmSystemTools::CXX_FILE_FORMAT) {
+ if (this->AutogenTarget.Sources.find(sf) ==
+ this->AutogenTarget.Sources.end()) {
+ auto muf = makeMUFile(sf, fullPath, false);
+ if (muf->SkipMoc || muf->SkipUic) {
+ this->AutogenTarget.Sources.emplace(sf, std::move(muf));
+ }
}
-
- // Check if the .ui file has uic options
- if (isUi && !skipUic) {
- std::string const uicOpts = sf->GetSafeProperty(AUTOUIC_OPTIONS_str);
+ } else if (this->Uic.Enabled && (ext == kw.ui)) {
+ // .ui file
+ std::string realPath = cmSystemTools::GetRealPath(fullPath);
+ bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN);
+ bool const skipUic =
+ (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC));
+ if (!skipUic) {
+ // Check if the .ui file has uic options
+ std::string const uicOpts = sf->GetSafeProperty(kw.AUTOUIC_OPTIONS);
if (!uicOpts.empty()) {
- this->Uic.FileFiles.push_back(absFile);
+ this->Uic.FileFiles.push_back(std::move(realPath));
std::vector<std::string> optsVec;
cmSystemTools::ExpandListArgument(uicOpts, optsVec);
this->Uic.FileOptions.push_back(std::move(optsVec));
}
+ } else {
+ // Register skipped .ui file
+ this->Uic.SkipUi.insert(std::move(realPath));
}
}
}
}
// Process GENERATED sources and headers
- if (this->Moc.Enabled || this->Uic.Enabled) {
- if (!this->AutogenTarget.SourcesGenerated.empty() ||
- !this->AutogenTarget.HeadersGenerated.empty()) {
- // Check status of policy CMP0071
- bool policyAccept = false;
- bool policyWarn = false;
- cmPolicies::PolicyStatus const CMP0071_status =
- makefile->GetPolicyStatus(cmPolicies::CMP0071);
- switch (CMP0071_status) {
- case cmPolicies::WARN:
- policyWarn = true;
- CM_FALLTHROUGH;
- case cmPolicies::OLD:
- // Ignore GENERATED file
- break;
- case cmPolicies::REQUIRED_IF_USED:
- case cmPolicies::REQUIRED_ALWAYS:
- case cmPolicies::NEW:
- // Process GENERATED file
- policyAccept = true;
- break;
+ if (this->MocOrUicEnabled() && !this->AutogenTarget.FilesGenerated.empty()) {
+ if (this->CMP0071Accept) {
+ // Let the autogen target depend on the GENERATED files
+ for (MUFile* muf : this->AutogenTarget.FilesGenerated) {
+ this->AutogenTarget.DependFiles.insert(muf->RealPath);
}
-
- if (policyAccept) {
- // Accept GENERATED sources
- for (std::string const& absFile :
- this->AutogenTarget.HeadersGenerated) {
- this->AutogenTarget.Headers.push_back(absFile);
- this->AutogenTarget.DependFiles.insert(absFile);
- }
- for (std::string const& absFile :
- this->AutogenTarget.SourcesGenerated) {
- this->AutogenTarget.Sources.push_back(absFile);
- this->AutogenTarget.DependFiles.insert(absFile);
- }
- } else {
- if (policyWarn) {
- std::string msg;
- msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071);
- msg += "\n";
- std::string tools;
- std::string property;
- if (this->Moc.Enabled && this->Uic.Enabled) {
- tools = "AUTOMOC and AUTOUIC";
- property = "SKIP_AUTOGEN";
- } else if (this->Moc.Enabled) {
- tools = "AUTOMOC";
- property = "SKIP_AUTOMOC";
- } else if (this->Uic.Enabled) {
- tools = "AUTOUIC";
- property = "SKIP_AUTOUIC";
- }
- msg += "For compatibility, CMake is excluding the GENERATED source "
- "file(s):\n";
- for (const std::string& absFile :
- this->AutogenTarget.HeadersGenerated) {
- msg.append(" ").append(Quoted(absFile)).append("\n");
- }
- for (const std::string& absFile :
- this->AutogenTarget.SourcesGenerated) {
- msg.append(" ").append(Quoted(absFile)).append("\n");
- }
- msg += "from processing by ";
- msg += tools;
- msg +=
- ". If any of the files should be processed, set CMP0071 to NEW. "
- "If any of the files should not be processed, "
- "explicitly exclude them by setting the source file property ";
- msg += property;
- msg += ":\n set_property(SOURCE file.h PROPERTY ";
- msg += property;
- msg += " ON)\n";
- makefile->IssueMessage(MessageType::AUTHOR_WARNING, msg);
- }
+ } else if (this->CMP0071Warn) {
+ std::string msg;
+ msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071);
+ msg += '\n';
+ std::string property;
+ if (this->Moc.Enabled && this->Uic.Enabled) {
+ property = kw.SKIP_AUTOGEN;
+ } else if (this->Moc.Enabled) {
+ property = kw.SKIP_AUTOMOC;
+ } else if (this->Uic.Enabled) {
+ property = kw.SKIP_AUTOUIC;
+ }
+ msg += "For compatibility, CMake is excluding the GENERATED source "
+ "file(s):\n";
+ for (MUFile* muf : this->AutogenTarget.FilesGenerated) {
+ msg += " ";
+ msg += Quoted(muf->RealPath);
+ msg += '\n';
}
+ msg += "from processing by ";
+ msg += cmQtAutoGen::Tools(this->Moc.Enabled, this->Uic.Enabled, false);
+ msg += ". If any of the files should be processed, set CMP0071 to NEW. "
+ "If any of the files should not be processed, "
+ "explicitly exclude them by setting the source file property ";
+ msg += property;
+ msg += ":\n set_property(SOURCE file.h PROPERTY ";
+ msg += property;
+ msg += " ON)\n";
+ makefile->IssueMessage(MessageType::AUTHOR_WARNING, msg);
}
}
- // Sort headers and sources
- if (this->Moc.Enabled || this->Uic.Enabled) {
- std::sort(this->AutogenTarget.Headers.begin(),
- this->AutogenTarget.Headers.end());
- std::sort(this->AutogenTarget.Sources.begin(),
- this->AutogenTarget.Sources.end());
- }
-
// Process qrc files
if (!this->Rcc.Qrcs.empty()) {
const bool modernQt = (this->QtVersion.Major >= 5);
// Target rcc options
std::vector<std::string> optionsTarget;
cmSystemTools::ExpandListArgument(
- this->Target->GetSafeProperty("AUTORCC_OPTIONS"), optionsTarget);
+ this->Target->GetSafeProperty(kw.AUTORCC_OPTIONS), optionsTarget);
// Check if file name is unique
for (Qrc& qrc : this->Rcc.Qrcs) {
@@ -938,7 +949,9 @@ bool cmQtAutoGenInitializer::InitScanFiles()
for (Qrc& qrc : this->Rcc.Qrcs) {
if (!qrc.Generated) {
std::string error;
- if (!RccListInputs(qrc.QrcFile, qrc.Resources, error)) {
+ RccLister const lister(this->Rcc.Executable,
+ this->Rcc.ExecutableFeatures->ListOptions);
+ if (!lister.list(qrc.QrcFile, qrc.Resources, error)) {
cmSystemTools::Error(error);
return false;
}
@@ -961,7 +974,7 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
// Files provided by the autogen target
std::vector<std::string> autogenProvides;
if (this->Moc.Enabled) {
- this->AddGeneratedSource(this->Moc.MocsCompilation, GeneratorT::MOC, true);
+ this->AddGeneratedSource(this->Moc.MocsCompilation, this->Moc, true);
autogenProvides.push_back(this->Moc.MocsCompilation);
}
@@ -1109,13 +1122,12 @@ bool cmQtAutoGenInitializer::InitRccTargets()
{
cmMakefile* makefile = this->Target->Target->GetMakefile();
cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
- auto rccTargetName = GetQtExecutableTargetName(this->QtVersion, "rcc");
for (Qrc const& qrc : this->Rcc.Qrcs) {
// Register info file as generated by CMake
makefile->AddCMakeOutputFile(qrc.InfoFile);
// Register file at target
- this->AddGeneratedSource(qrc.RccFile, GeneratorT::RCC);
+ this->AddGeneratedSource(qrc.RccFile, this->Rcc);
std::vector<std::string> ccOutput;
ccOutput.push_back(qrc.RccFile);
@@ -1174,8 +1186,8 @@ bool cmQtAutoGenInitializer::InitRccTargets()
if (!this->TargetsFolder.empty()) {
autoRccTarget->SetProperty("FOLDER", this->TargetsFolder.c_str());
}
- if (!rccTargetName.empty()) {
- autoRccTarget->AddUtility(rccTargetName, makefile);
+ if (!this->Rcc.ExecutableTargetName.empty()) {
+ autoRccTarget->AddUtility(this->Rcc.ExecutableTargetName, makefile);
}
}
// Add autogen target to the origin target dependencies
@@ -1195,8 +1207,8 @@ bool cmQtAutoGenInitializer::InitRccTargets()
// Add resource file to the custom command dependencies
ccDepends.push_back(fileName);
}
- if (!rccTargetName.empty()) {
- ccDepends.push_back(rccTargetName);
+ if (!this->Rcc.ExecutableTargetName.empty()) {
+ ccDepends.push_back(this->Rcc.ExecutableTargetName);
}
makefile->AddCustomCommandToOutput(ccOutput, ccByproducts, ccDepends,
/*main_dependency*/ std::string(),
@@ -1222,7 +1234,7 @@ bool cmQtAutoGenInitializer::SetupCustomTargets()
}
// Generate autogen target info file
- if (this->Moc.Enabled || this->Uic.Enabled) {
+ if (this->MocOrUicEnabled()) {
// Write autogen target info files
if (!this->SetupWriteAutogenInfo()) {
return false;
@@ -1262,22 +1274,131 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
ofs.Write("AM_INCLUDE_DIR", this->Dir.Include);
ofs.WriteConfig("AM_INCLUDE_DIR", this->Dir.ConfigInclude);
- ofs.Write("# Files\n");
- ofs.WriteStrings("AM_SOURCES", this->AutogenTarget.Sources);
- ofs.WriteStrings("AM_HEADERS", this->AutogenTarget.Headers);
- ofs.Write("AM_SETTINGS_FILE", this->AutogenTarget.SettingsFile);
- ofs.WriteConfig("AM_SETTINGS_FILE",
- this->AutogenTarget.ConfigSettingsFile);
+ std::vector<std::string> headers;
+ std::vector<std::string> headersFlags;
+ std::vector<std::string> headersBuildPaths;
+ std::vector<std::string> sources;
+ std::vector<std::string> sourcesFlags;
+ std::set<std::string> moc_skip;
+ std::set<std::string> uic_skip;
+
+ // Filter headers
+ {
+ auto headerCount = this->AutogenTarget.Headers.size();
+ headers.reserve(headerCount);
+ headersFlags.reserve(headerCount);
+
+ std::vector<MUFile const*> sortedHeaders;
+ {
+ sortedHeaders.reserve(headerCount);
+ for (auto const& pair : this->AutogenTarget.Headers) {
+ sortedHeaders.emplace_back(pair.second.get());
+ }
+ std::sort(sortedHeaders.begin(), sortedHeaders.end(),
+ [](MUFile const* a, MUFile const* b) {
+ return (a->RealPath < b->RealPath);
+ });
+ }
+
+ for (MUFile const* const muf : sortedHeaders) {
+ if (muf->Generated && !this->CMP0071Accept) {
+ continue;
+ }
+ if (muf->SkipMoc) {
+ moc_skip.insert(muf->RealPath);
+ }
+ if (muf->SkipUic) {
+ uic_skip.insert(muf->RealPath);
+ }
+ if (muf->MocIt || muf->UicIt) {
+ headers.emplace_back(muf->RealPath);
+ std::string flags;
+ flags += muf->MocIt ? 'M' : 'm';
+ flags += muf->UicIt ? 'U' : 'u';
+ headersFlags.emplace_back(std::move(flags));
+ }
+ }
+ }
+ // Header build paths
+ {
+ cmFilePathChecksum const fpathCheckSum(makefile);
+ std::unordered_set<std::string> emitted;
+ for (std::string const& hdr : headers) {
+ std::string basePath = fpathCheckSum.getPart(hdr);
+ basePath += "/moc_";
+ basePath += cmSystemTools::GetFilenameWithoutLastExtension(hdr);
+ for (unsigned int ii = 1; ii != 1024; ++ii) {
+ std::string path = basePath;
+ if (ii > 1) {
+ path += '_';
+ path += std::to_string(ii);
+ }
+ path += ".cpp";
+ if (emitted.emplace(path).second) {
+ headersBuildPaths.emplace_back(std::move(path));
+ break;
+ }
+ }
+ }
+ }
+
+ // Filter sources
+ {
+ auto sourcesCount = this->AutogenTarget.Sources.size();
+ sources.reserve(sourcesCount);
+ sourcesFlags.reserve(sourcesCount);
+
+ std::vector<MUFile const*> sorted;
+ sorted.reserve(sourcesCount);
+ for (auto const& pair : this->AutogenTarget.Sources) {
+ sorted.emplace_back(pair.second.get());
+ }
+ std::sort(sorted.begin(), sorted.end(),
+ [](MUFile const* a, MUFile const* b) {
+ return (a->RealPath < b->RealPath);
+ });
+
+ for (MUFile const* const muf : sorted) {
+ if (muf->Generated && !this->CMP0071Accept) {
+ continue;
+ }
+ if (muf->SkipMoc) {
+ moc_skip.insert(muf->RealPath);
+ }
+ if (muf->SkipUic) {
+ uic_skip.insert(muf->RealPath);
+ }
+ if (muf->MocIt || muf->UicIt) {
+ sources.emplace_back(muf->RealPath);
+ std::string flags;
+ flags += muf->MocIt ? 'M' : 'm';
+ flags += muf->UicIt ? 'U' : 'u';
+ sourcesFlags.emplace_back(std::move(flags));
+ }
+ }
+ }
ofs.Write("# Qt\n");
ofs.WriteUInt("AM_QT_VERSION_MAJOR", this->QtVersion.Major);
ofs.Write("AM_QT_MOC_EXECUTABLE", this->Moc.Executable);
ofs.Write("AM_QT_UIC_EXECUTABLE", this->Uic.Executable);
+ ofs.Write("# Files\n");
+ ofs.Write("AM_CMAKE_EXECUTABLE", cmSystemTools::GetCMakeCommand());
+ ofs.Write("AM_SETTINGS_FILE", this->AutogenTarget.SettingsFile);
+ ofs.WriteConfig("AM_SETTINGS_FILE",
+ this->AutogenTarget.ConfigSettingsFile);
+ ofs.Write("AM_PARSE_CACHE_FILE", this->AutogenTarget.ParseCacheFile);
+ ofs.WriteStrings("AM_HEADERS", headers);
+ ofs.WriteStrings("AM_HEADERS_FLAGS", headersFlags);
+ ofs.WriteStrings("AM_HEADERS_BUILD_PATHS", headersBuildPaths);
+ ofs.WriteStrings("AM_SOURCES", sources);
+ ofs.WriteStrings("AM_SOURCES_FLAGS", sourcesFlags);
+
// Write moc settings
if (this->Moc.Enabled) {
ofs.Write("# MOC settings\n");
- ofs.WriteStrings("AM_MOC_SKIP", this->Moc.Skip);
+ ofs.WriteStrings("AM_MOC_SKIP", moc_skip);
ofs.WriteStrings("AM_MOC_DEFINITIONS", this->Moc.Defines);
ofs.WriteConfigStrings("AM_MOC_DEFINITIONS", this->Moc.ConfigDefines);
ofs.WriteStrings("AM_MOC_INCLUDES", this->Moc.Includes);
@@ -1294,8 +1415,11 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
// Write uic settings
if (this->Uic.Enabled) {
+ // Add skipped .ui files
+ uic_skip.insert(this->Uic.SkipUi.begin(), this->Uic.SkipUi.end());
+
ofs.Write("# UIC settings\n");
- ofs.WriteStrings("AM_UIC_SKIP", this->Uic.Skip);
+ ofs.WriteStrings("AM_UIC_SKIP", uic_skip);
ofs.WriteStrings("AM_UIC_TARGET_OPTIONS", this->Uic.Options);
ofs.WriteConfigStrings("AM_UIC_TARGET_OPTIONS", this->Uic.ConfigOptions);
ofs.WriteStrings("AM_UIC_OPTIONS_FILES", this->Uic.FileFiles);
@@ -1332,7 +1456,8 @@ bool cmQtAutoGenInitializer::SetupWriteRccInfo()
ofs.Write("# Rcc executable\n");
ofs.Write("ARCC_RCC_EXECUTABLE", this->Rcc.Executable);
- ofs.WriteStrings("ARCC_RCC_LIST_OPTIONS", this->Rcc.ListOptions);
+ ofs.WriteStrings("ARCC_RCC_LIST_OPTIONS",
+ this->Rcc.ExecutableFeatures->ListOptions);
ofs.Write("# Rcc job\n");
ofs.Write("ARCC_LOCK_FILE", qrc.LockFile);
@@ -1353,23 +1478,74 @@ bool cmQtAutoGenInitializer::SetupWriteRccInfo()
return true;
}
-void cmQtAutoGenInitializer::AddGeneratedSource(std::string const& filename,
- GeneratorT genType,
+void cmQtAutoGenInitializer::RegisterGeneratedSource(
+ std::string const& filename)
+{
+ cmMakefile* makefile = this->Target->Target->GetMakefile();
+ cmSourceFile* gFile = makefile->GetOrCreateSource(filename, true);
+ gFile->SetProperty("GENERATED", "1");
+ gFile->SetProperty("SKIP_AUTOGEN", "1");
+}
+
+bool cmQtAutoGenInitializer::AddGeneratedSource(std::string const& filename,
+ GenVarsT const& genVars,
bool prepend)
{
- // Register source file in makefile
+ // Register source at makefile
+ this->RegisterGeneratedSource(filename);
+ // Add source file to target
+ this->Target->AddSource(filename, prepend);
+ // Add source file to source group
+ return this->AddToSourceGroup(filename, genVars.GenNameUpper);
+}
+
+bool cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName,
+ std::string const& genNameUpper)
+{
cmMakefile* makefile = this->Target->Target->GetMakefile();
+ cmSourceGroup* sourceGroup = nullptr;
+ // Acquire source group
{
- cmSourceFile* gFile = makefile->GetOrCreateSource(filename, true);
- gFile->SetProperty("GENERATED", "1");
- gFile->SetProperty("SKIP_AUTOGEN", "On");
+ std::string property;
+ std::string groupName;
+ {
+ // Prefer generator specific source group name
+ std::array<std::string, 2> props{ { genNameUpper + "_SOURCE_GROUP",
+ "AUTOGEN_SOURCE_GROUP" } };
+ for (std::string& prop : props) {
+ const char* propName = makefile->GetState()->GetGlobalProperty(prop);
+ if ((propName != nullptr) && (*propName != '\0')) {
+ groupName = propName;
+ property = std::move(prop);
+ break;
+ }
+ }
+ }
+ // Generate a source group on demand
+ if (!groupName.empty()) {
+ sourceGroup = makefile->GetOrCreateSourceGroup(groupName);
+ if (sourceGroup == nullptr) {
+ std::string err;
+ err += genNameUpper;
+ err += " error in ";
+ err += property;
+ err += ": Could not find or create the source group ";
+ err += cmQtAutoGen::Quoted(groupName);
+ cmSystemTools::Error(err);
+ return false;
+ }
+ }
}
+ if (sourceGroup != nullptr) {
+ sourceGroup->AddGroupFile(fileName);
+ }
+ return true;
+}
- // Add source file to source group
- AddToSourceGroup(makefile, filename, genType);
-
- // Add source file to target
- this->Target->AddSource(filename, prepend);
+void cmQtAutoGenInitializer::AddCleanFile(std::string const& fileName)
+{
+ Target->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", fileName.c_str(),
+ false);
}
static unsigned int CharPtrToUInt(const char* const input)
@@ -1384,8 +1560,12 @@ static unsigned int CharPtrToUInt(const char* const input)
static std::vector<cmQtAutoGen::IntegerVersion> GetKnownQtVersions(
cmGeneratorTarget const* target)
{
- cmMakefile* makefile = target->Target->GetMakefile();
+ // Qt version variable prefixes
+ static std::array<std::string, 3> const prefixes{ { "Qt6Core", "Qt5Core",
+ "QT" } };
+
std::vector<cmQtAutoGen::IntegerVersion> result;
+ result.reserve(prefixes.size() * 2);
// Adds a version to the result (nullptr safe)
auto addVersion = [&result](const char* major, const char* minor) {
cmQtAutoGen::IntegerVersion ver(CharPtrToUInt(major),
@@ -1394,8 +1574,7 @@ static std::vector<cmQtAutoGen::IntegerVersion> GetKnownQtVersions(
result.emplace_back(ver);
}
};
- // Qt version variable prefixes
- std::array<std::string, 3> const prefixes{ { "Qt6Core", "Qt5Core", "QT" } };
+ cmMakefile* makefile = target->Target->GetMakefile();
// Read versions from variables
for (const std::string& prefix : prefixes) {
@@ -1439,181 +1618,95 @@ cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target)
return res;
}
-std::pair<bool, std::string> cmQtAutoGenInitializer::GetQtExecutable(
- const std::string& executable, bool ignoreMissingTarget, std::string* output)
+bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
+ const std::string& executable,
+ bool ignoreMissingTarget) const
{
- const std::string upperExecutable = cmSystemTools::UpperCase(executable);
- std::string result = this->Target->Target->GetSafeProperty(
- "AUTO" + upperExecutable + "_EXECUTABLE");
- if (!result.empty()) {
- cmListFileBacktrace lfbt =
- this->Target->Target->GetMakefile()->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
- std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(result);
- result = cge->Evaluate(this->Target->GetLocalGenerator(), "");
-
- return std::make_pair(true, result);
- }
-
- std::string err;
-
- // Find executable
- {
- const std::string targetName =
- GetQtExecutableTargetName(this->QtVersion, executable);
- if (targetName.empty()) {
- err = "The AUTO" + upperExecutable + " feature ";
- err += "supports only Qt 4, Qt 5 and Qt 6.";
- } else {
- cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
- cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse(targetName);
- if (tgt != nullptr) {
- if (tgt->IsImported()) {
- result = tgt->ImportedGetLocation("");
- } else {
- result = tgt->GetLocation("");
- }
- } else {
- if (ignoreMissingTarget) {
- return std::make_pair(true, "");
- }
-
- err = "Could not find target " + targetName;
- }
- }
- }
-
- // Test executable
- if (err.empty()) {
- this->GlobalInitializer->GetExecutableTestOutput(executable, result, err,
- output);
- }
-
- // Print error
- if (!err.empty()) {
- std::string msg = "AutoGen (";
+ auto print_err = [this, &genVars](std::string const& err) {
+ std::string msg = genVars.GenNameUpper;
+ msg += " for target ";
msg += this->Target->GetName();
- msg += "): ";
+ msg += ": ";
msg += err;
cmSystemTools::Error(msg);
- return std::make_pair(false, "");
- }
-
- return std::make_pair(true, result);
-}
-
-bool cmQtAutoGenInitializer::GetMocExecutable()
-{
- const auto result = this->GetQtExecutable("moc", false, nullptr);
- this->Moc.Executable = result.second;
- return result.first;
-}
-
-bool cmQtAutoGenInitializer::GetUicExecutable()
-{
- const auto result = this->GetQtExecutable("uic", true, nullptr);
- this->Uic.Executable = result.second;
- return result.first;
-}
+ };
-bool cmQtAutoGenInitializer::GetRccExecutable()
-{
- std::string stdOut;
- const auto result = this->GetQtExecutable("rcc", false, &stdOut);
- this->Rcc.Executable = result.second;
- if (!result.first) {
- return false;
- }
+ // Custom executable
+ {
+ std::string const prop = genVars.GenNameUpper + "_EXECUTABLE";
+ std::string const val = this->Target->Target->GetSafeProperty(prop);
+ if (!val.empty()) {
+ // Evaluate generator expression
+ {
+ cmListFileBacktrace lfbt =
+ this->Target->Target->GetMakefile()->GetBacktrace();
+ cmGeneratorExpression ge(lfbt);
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(val);
+ genVars.Executable =
+ cge->Evaluate(this->Target->GetLocalGenerator(), "");
+ }
+ if (genVars.Executable.empty() && !ignoreMissingTarget) {
+ print_err(prop + " evaluates to an empty value");
+ return false;
+ }
- if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) {
- if (stdOut.find("--list") != std::string::npos) {
- this->Rcc.ListOptions.emplace_back("--list");
- } else {
- this->Rcc.ListOptions.emplace_back("-list");
+ // Create empty compiler features.
+ genVars.ExecutableFeatures =
+ std::make_shared<cmQtAutoGen::CompilerFeatures>();
+ return true;
}
}
- return true;
-}
-/// @brief Reads the resource files list from from a .qrc file
-/// @arg fileName Must be the absolute path of the .qrc file
-/// @return True if the rcc file was successfully read
-bool cmQtAutoGenInitializer::RccListInputs(std::string const& fileName,
- std::vector<std::string>& files,
- std::string& error)
-{
- if (!cmSystemTools::FileExists(fileName)) {
- error = "rcc resource file does not exist:\n ";
- error += Quoted(fileName);
- error += "\n";
- return false;
- }
- if (!this->Rcc.ListOptions.empty()) {
- // Use rcc for file listing
- if (this->Rcc.Executable.empty()) {
- error = "rcc executable not available";
- return false;
+ // Find executable target
+ {
+ // Find executable target name
+ std::string targetName;
+ if (this->QtVersion.Major == 4) {
+ targetName = "Qt4::";
+ } else if (this->QtVersion.Major == 5) {
+ targetName = "Qt5::";
+ } else if (this->QtVersion.Major == 6) {
+ targetName = "Qt6::";
}
-
- // Run rcc list command in the directory of the qrc file with the
- // pathless
- // qrc file name argument. This way rcc prints relative paths.
- // This avoids issues on Windows when the qrc file is in a path that
- // contains non-ASCII characters.
- std::string const fileDir = cmSystemTools::GetFilenamePath(fileName);
- std::string const fileNameName = cmSystemTools::GetFilenameName(fileName);
-
- bool result = false;
- int retVal = 0;
- std::string rccStdOut;
- std::string rccStdErr;
- {
- std::vector<std::string> cmd;
- cmd.push_back(this->Rcc.Executable);
- cmd.insert(cmd.end(), this->Rcc.ListOptions.begin(),
- this->Rcc.ListOptions.end());
- cmd.push_back(fileNameName);
- result = cmSystemTools::RunSingleCommand(
- cmd, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(),
- cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto);
- }
- if (!result || retVal) {
- error = "rcc list process failed for:\n ";
- error += Quoted(fileName);
- error += "\n";
- error += rccStdOut;
- error += "\n";
- error += rccStdErr;
- error += "\n";
+ targetName += executable;
+
+ // Find target
+ cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
+ cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(targetName);
+ if (target != nullptr) {
+ genVars.ExecutableTargetName = targetName;
+ genVars.ExecutableTarget = target;
+ if (target->IsImported()) {
+ genVars.Executable = target->ImportedGetLocation("");
+ } else {
+ genVars.Executable = target->GetLocation("");
+ }
+ } else {
+ if (ignoreMissingTarget) {
+ // Create empty compiler features.
+ genVars.ExecutableFeatures =
+ std::make_shared<cmQtAutoGen::CompilerFeatures>();
+ return true;
+ }
+ std::string err = "Could not find ";
+ err += executable;
+ err += " executable target ";
+ err += targetName;
+ print_err(err);
return false;
}
- if (!RccListParseOutput(rccStdOut, rccStdErr, files, error)) {
+ }
+
+ // Get executable features
+ {
+ std::string err;
+ genVars.ExecutableFeatures = this->GlobalInitializer->GetCompilerFeatures(
+ executable, genVars.Executable, err);
+ if (!genVars.ExecutableFeatures) {
+ print_err(err);
return false;
}
- } else {
- // We can't use rcc for the file listing.
- // Read the qrc file content into string and parse it.
- {
- std::string qrcContents;
- {
- cmsys::ifstream ifs(fileName.c_str());
- if (ifs) {
- std::ostringstream osst;
- osst << ifs.rdbuf();
- qrcContents = osst.str();
- } else {
- error = "rcc file not readable:\n ";
- error += Quoted(fileName);
- error += "\n";
- return false;
- }
- }
- // Parse string content
- RccListParseContent(qrcContents, files);
- }
}
- // Convert relative paths to absolute paths
- RccListConvertFullPath(cmSystemTools::GetFilenamePath(fileName), files);
return true;
}
diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h
index 781dd15d6..aa073d1fd 100644
--- a/Source/cmQtAutoGenInitializer.h
+++ b/Source/cmQtAutoGenInitializer.h
@@ -8,15 +8,18 @@
#include "cmQtAutoGen.h"
#include <map>
+#include <memory> // IWYU pragma: keep
#include <ostream>
#include <set>
#include <string>
+#include <unordered_map>
#include <utility>
#include <vector>
class cmGeneratorTarget;
class cmTarget;
class cmQtAutoGenGlobalInitializer;
+class cmSourceFile;
/// @brief Initializes the QtAutoGen generators
class cmQtAutoGenInitializer : public cmQtAutoGen
@@ -40,6 +43,38 @@ public:
std::vector<std::string> Resources;
};
+ /// @brief Moc/Uic file
+ struct MUFile
+ {
+ std::string RealPath;
+ cmSourceFile* SF = nullptr;
+ bool Generated = false;
+ bool SkipMoc = false;
+ bool SkipUic = false;
+ bool MocIt = false;
+ bool UicIt = false;
+ };
+ typedef std::unique_ptr<MUFile> MUFileHandle;
+
+ /// @brief Abstract moc/uic/rcc generator variables base class
+ struct GenVarsT
+ {
+ bool Enabled = false;
+ // Generator type/name
+ GenT Gen;
+ std::string const& GenNameUpper;
+ // Executable
+ std::string ExecutableTargetName;
+ cmGeneratorTarget* ExecutableTarget = nullptr;
+ std::string Executable;
+ CompilerFeaturesHandle ExecutableFeatures;
+
+ /// @brief Constructor
+ GenVarsT(GenT gen)
+ : Gen(gen)
+ , GenNameUpper(cmQtAutoGen::GeneratorNameUpper(gen)){};
+ };
+
/// @brief Writes a CMake info file
class InfoWriter
{
@@ -88,6 +123,12 @@ public:
bool SetupCustomTargets();
private:
+ /// @brief If moc or uic is enabled, the autogen target will be generated
+ bool MocOrUicEnabled() const
+ {
+ return (this->Moc.Enabled || this->Uic.Enabled);
+ }
+
bool InitMoc();
bool InitUic();
bool InitRcc();
@@ -99,20 +140,15 @@ private:
bool SetupWriteAutogenInfo();
bool SetupWriteRccInfo();
- void AddGeneratedSource(std::string const& filename, GeneratorT genType,
+ void RegisterGeneratedSource(std::string const& filename);
+ bool AddGeneratedSource(std::string const& filename, GenVarsT const& genVars,
bool prepend = false);
+ bool AddToSourceGroup(std::string const& fileName,
+ std::string const& genNameUpper);
+ void AddCleanFile(std::string const& fileName);
- bool GetMocExecutable();
- bool GetUicExecutable();
- bool GetRccExecutable();
-
- bool RccListInputs(std::string const& fileName,
- std::vector<std::string>& files,
- std::string& errorMessage);
-
- std::pair<bool, std::string> GetQtExecutable(const std::string& executable,
- bool ignoreMissingTarget,
- std::string* output);
+ bool GetQtExecutable(GenVarsT& genVars, const std::string& executable,
+ bool ignoreMissingTarget) const;
private:
cmQtAutoGenGlobalInitializer* GlobalInitializer;
@@ -125,6 +161,8 @@ private:
std::vector<std::string> ConfigsList;
std::string Verbosity;
std::string TargetsFolder;
+ bool CMP0071Accept = false;
+ bool CMP0071Warn = false;
/// @brief Common directories
struct
@@ -146,53 +184,57 @@ private:
// Configuration files
std::string InfoFile;
std::string SettingsFile;
+ std::string ParseCacheFile;
std::map<std::string, std::string> ConfigSettingsFile;
// Dependencies
bool DependOrigin = false;
std::set<std::string> DependFiles;
std::set<cmTarget*> DependTargets;
// Sources to process
- std::vector<std::string> Headers;
- std::vector<std::string> Sources;
- std::vector<std::string> HeadersGenerated;
- std::vector<std::string> SourcesGenerated;
+ std::unordered_map<cmSourceFile*, MUFileHandle> Headers;
+ std::unordered_map<cmSourceFile*, MUFileHandle> Sources;
+ std::vector<MUFile*> FilesGenerated;
} AutogenTarget;
/// @brief Moc only variables
- struct
+ struct MocT : public GenVarsT
{
- bool Enabled = false;
- std::string Executable;
std::string PredefsCmd;
- std::set<std::string> Skip;
std::vector<std::string> Includes;
std::map<std::string, std::vector<std::string>> ConfigIncludes;
std::set<std::string> Defines;
std::map<std::string, std::set<std::string>> ConfigDefines;
std::string MocsCompilation;
+
+ /// @brief Constructor
+ MocT()
+ : GenVarsT(GenT::MOC){};
} Moc;
- ///@brief Uic only variables
- struct
+ /// @brief Uic only variables
+ struct UicT : public GenVarsT
{
- bool Enabled = false;
- std::string Executable;
- std::set<std::string> Skip;
+ std::set<std::string> SkipUi;
std::vector<std::string> SearchPaths;
std::vector<std::string> Options;
std::map<std::string, std::vector<std::string>> ConfigOptions;
std::vector<std::string> FileFiles;
std::vector<std::vector<std::string>> FileOptions;
+
+ /// @brief Constructor
+ UicT()
+ : GenVarsT(GenT::UIC){};
} Uic;
/// @brief Rcc only variables
- struct
+ struct RccT : public GenVarsT
{
- bool Enabled = false;
bool GlobalTarget = false;
- std::string Executable;
- std::vector<std::string> ListOptions;
std::vector<Qrc> Qrcs;
+
+ /// @brief Constructor
+ RccT()
+ : GenVarsT(GenT::RCC){};
} Rcc;
};
diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx
index e2d7debed..e1c435be0 100644
--- a/Source/cmQtAutoGenerator.cxx
+++ b/Source/cmQtAutoGenerator.cxx
@@ -14,10 +14,33 @@
#include "cmSystemTools.h"
#include "cmake.h"
-#include <algorithm>
-#include <utility>
+cmQtAutoGenerator::Logger::Logger()
+{
+ // Initialize logger
+ {
+ std::string verbose;
+ if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) {
+ unsigned long iVerbose = 0;
+ if (cmSystemTools::StringToULong(verbose.c_str(), &iVerbose)) {
+ SetVerbosity(static_cast<unsigned int>(iVerbose));
+ } else {
+ // Non numeric verbosity
+ SetVerbose(cmSystemTools::IsOn(verbose));
+ }
+ }
+ }
+ {
+ std::string colorEnv;
+ cmSystemTools::GetEnv("COLOR", colorEnv);
+ if (!colorEnv.empty()) {
+ SetColorOutput(cmSystemTools::IsOn(colorEnv));
+ } else {
+ SetColorOutput(true);
+ }
+ }
+}
-// -- Class methods
+cmQtAutoGenerator::Logger::~Logger() = default;
void cmQtAutoGenerator::Logger::RaiseVerbosity(std::string const& value)
{
@@ -43,8 +66,8 @@ std::string cmQtAutoGenerator::Logger::HeadLine(std::string const& title)
return head;
}
-void cmQtAutoGenerator::Logger::Info(GeneratorT genType,
- std::string const& message)
+void cmQtAutoGenerator::Logger::Info(GenT genType,
+ std::string const& message) const
{
std::string msg = GeneratorName(genType);
msg += ": ";
@@ -58,8 +81,8 @@ void cmQtAutoGenerator::Logger::Info(GeneratorT genType,
}
}
-void cmQtAutoGenerator::Logger::Warning(GeneratorT genType,
- std::string const& message)
+void cmQtAutoGenerator::Logger::Warning(GenT genType,
+ std::string const& message) const
{
std::string msg;
if (message.find('\n') == std::string::npos) {
@@ -82,9 +105,9 @@ void cmQtAutoGenerator::Logger::Warning(GeneratorT genType,
}
}
-void cmQtAutoGenerator::Logger::WarningFile(GeneratorT genType,
+void cmQtAutoGenerator::Logger::WarningFile(GenT genType,
std::string const& filename,
- std::string const& message)
+ std::string const& message) const
{
std::string msg = " ";
msg += Quoted(filename);
@@ -94,8 +117,8 @@ void cmQtAutoGenerator::Logger::WarningFile(GeneratorT genType,
Warning(genType, msg);
}
-void cmQtAutoGenerator::Logger::Error(GeneratorT genType,
- std::string const& message)
+void cmQtAutoGenerator::Logger::Error(GenT genType,
+ std::string const& message) const
{
std::string msg;
msg += HeadLine(GeneratorName(genType) + " error");
@@ -111,9 +134,9 @@ void cmQtAutoGenerator::Logger::Error(GeneratorT genType,
}
}
-void cmQtAutoGenerator::Logger::ErrorFile(GeneratorT genType,
+void cmQtAutoGenerator::Logger::ErrorFile(GenT genType,
std::string const& filename,
- std::string const& message)
+ std::string const& message) const
{
std::string emsg = " ";
emsg += Quoted(filename);
@@ -124,8 +147,8 @@ void cmQtAutoGenerator::Logger::ErrorFile(GeneratorT genType,
}
void cmQtAutoGenerator::Logger::ErrorCommand(
- GeneratorT genType, std::string const& message,
- std::vector<std::string> const& command, std::string const& output)
+ GenT genType, std::string const& message,
+ std::vector<std::string> const& command, std::string const& output) const
{
std::string msg;
msg.push_back('\n');
@@ -153,528 +176,101 @@ void cmQtAutoGenerator::Logger::ErrorCommand(
}
}
-std::string cmQtAutoGenerator::FileSystem::GetRealPath(
- std::string const& filename)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::GetRealPath(filename);
-}
-
-std::string cmQtAutoGenerator::FileSystem::CollapseCombinedPath(
- std::string const& dir, std::string const& file)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::CollapseCombinedPath(dir, file);
-}
-
-void cmQtAutoGenerator::FileSystem::SplitPath(
- const std::string& p, std::vector<std::string>& components,
- bool expand_home_dir)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- cmSystemTools::SplitPath(p, components, expand_home_dir);
-}
-
-std::string cmQtAutoGenerator::FileSystem::JoinPath(
- const std::vector<std::string>& components)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::JoinPath(components);
-}
-
-std::string cmQtAutoGenerator::FileSystem::JoinPath(
- std::vector<std::string>::const_iterator first,
- std::vector<std::string>::const_iterator last)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::JoinPath(first, last);
-}
-
-std::string cmQtAutoGenerator::FileSystem::GetFilenameWithoutLastExtension(
- const std::string& filename)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::GetFilenameWithoutLastExtension(filename);
-}
-
-std::string cmQtAutoGenerator::FileSystem::SubDirPrefix(
- std::string const& filename)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmQtAutoGen::SubDirPrefix(filename);
-}
-
-void cmQtAutoGenerator::FileSystem::setupFilePathChecksum(
- std::string const& currentSrcDir, std::string const& currentBinDir,
- std::string const& projectSrcDir, std::string const& projectBinDir)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- FilePathChecksum_.setupParentDirs(currentSrcDir, currentBinDir,
- projectSrcDir, projectBinDir);
-}
-
-std::string cmQtAutoGenerator::FileSystem::GetFilePathChecksum(
- std::string const& filename)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return FilePathChecksum_.getPart(filename);
-}
-
-bool cmQtAutoGenerator::FileSystem::FileExists(std::string const& filename)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::FileExists(filename);
-}
-
-bool cmQtAutoGenerator::FileSystem::FileExists(std::string const& filename,
- bool isFile)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::FileExists(filename, isFile);
-}
-
-unsigned long cmQtAutoGenerator::FileSystem::FileLength(
- std::string const& filename)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::FileLength(filename);
-}
-
-bool cmQtAutoGenerator::FileSystem::FileIsOlderThan(
- std::string const& buildFile, std::string const& sourceFile,
- std::string* error)
-{
- bool res(false);
- int result = 0;
- {
- std::lock_guard<std::mutex> lock(Mutex_);
- res = cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result);
- }
- if (res) {
- res = (result < 0);
- } else {
- if (error != nullptr) {
- error->append(
- "File modification time comparison failed for the files\n ");
- error->append(Quoted(buildFile));
- error->append("\nand\n ");
- error->append(Quoted(sourceFile));
- }
- }
- return res;
-}
-
-bool cmQtAutoGenerator::FileSystem::FileRead(std::string& content,
- std::string const& filename,
- std::string* error)
-{
- bool success = false;
- if (FileExists(filename, true)) {
- unsigned long const length = FileLength(filename);
- {
- std::lock_guard<std::mutex> lock(Mutex_);
- cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
- if (ifs) {
- content.reserve(length);
- content.assign(std::istreambuf_iterator<char>{ ifs },
- std::istreambuf_iterator<char>{});
- if (ifs) {
- success = true;
- } else {
- content.clear();
- if (error != nullptr) {
- error->append("Reading from the file failed.");
- }
- }
- } else if (error != nullptr) {
- error->append("Opening the file for reading failed.");
- }
- }
- } else if (error != nullptr) {
- error->append(
- "The file does not exist, is not readable or is a directory.");
- }
- return success;
-}
-
-bool cmQtAutoGenerator::FileSystem::FileRead(GeneratorT genType,
- std::string& content,
- std::string const& filename)
-{
- std::string error;
- if (!FileRead(content, filename, &error)) {
- Log()->ErrorFile(genType, filename, error);
- return false;
- }
- return true;
-}
-
-bool cmQtAutoGenerator::FileSystem::FileWrite(std::string const& filename,
- std::string const& content,
- std::string* error)
-{
- bool success = false;
- // Make sure the parent directory exists
- if (MakeParentDirectory(filename)) {
- std::lock_guard<std::mutex> lock(Mutex_);
- cmsys::ofstream outfile;
- outfile.open(filename.c_str(),
- (std::ios::out | std::ios::binary | std::ios::trunc));
- if (outfile) {
- outfile << content;
- // Check for write errors
- if (outfile.good()) {
- success = true;
- } else {
- if (error != nullptr) {
- error->assign("File writing failed");
- }
- }
- } else {
- if (error != nullptr) {
- error->assign("Opening file for writing failed");
- }
- }
- } else {
- if (error != nullptr) {
- error->assign("Could not create parent directory");
- }
- }
- return success;
-}
-
-bool cmQtAutoGenerator::FileSystem::FileWrite(GeneratorT genType,
- std::string const& filename,
- std::string const& content)
-{
- std::string error;
- if (!FileWrite(filename, content, &error)) {
- Log()->ErrorFile(genType, filename, error);
- return false;
- }
- return true;
-}
-
-bool cmQtAutoGenerator::FileSystem::FileDiffers(std::string const& filename,
- std::string const& content)
-{
- bool differs = true;
- {
- std::string oldContents;
- if (FileRead(oldContents, filename)) {
- differs = (oldContents != content);
- }
- }
- return differs;
-}
-
-bool cmQtAutoGenerator::FileSystem::FileRemove(std::string const& filename)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::RemoveFile(filename);
-}
-
-bool cmQtAutoGenerator::FileSystem::Touch(std::string const& filename,
- bool create)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::Touch(filename, create);
-}
-
-bool cmQtAutoGenerator::FileSystem::MakeDirectory(std::string const& dirname)
-{
- std::lock_guard<std::mutex> lock(Mutex_);
- return cmSystemTools::MakeDirectory(dirname);
-}
-
-bool cmQtAutoGenerator::FileSystem::MakeDirectory(GeneratorT genType,
- std::string const& dirname)
-{
- if (!MakeDirectory(dirname)) {
- Log()->ErrorFile(genType, dirname, "Could not create directory");
- return false;
- }
- return true;
-}
-
-bool cmQtAutoGenerator::FileSystem::MakeParentDirectory(
- std::string const& filename)
+bool cmQtAutoGenerator::MakeParentDirectory(std::string const& filename)
{
bool success = true;
std::string const dirName = cmSystemTools::GetFilenamePath(filename);
if (!dirName.empty()) {
- success = MakeDirectory(dirName);
+ success = cmSystemTools::MakeDirectory(dirName);
}
return success;
}
-bool cmQtAutoGenerator::FileSystem::MakeParentDirectory(
- GeneratorT genType, std::string const& filename)
+bool cmQtAutoGenerator::FileRead(std::string& content,
+ std::string const& filename,
+ std::string* error)
{
- if (!MakeParentDirectory(filename)) {
- Log()->ErrorFile(genType, filename, "Could not create parent directory");
+ content.clear();
+ if (!cmSystemTools::FileExists(filename, true)) {
+ if (error != nullptr) {
+ *error = "Not a file.";
+ }
return false;
}
- return true;
-}
-int cmQtAutoGenerator::ReadOnlyProcessT::PipeT::init(uv_loop_t* uv_loop,
- ReadOnlyProcessT* process)
-{
- Process_ = process;
- Target_ = nullptr;
- return UVPipe_.init(*uv_loop, 0, this);
-}
-
-int cmQtAutoGenerator::ReadOnlyProcessT::PipeT::startRead(std::string* target)
-{
- Target_ = target;
- return uv_read_start(uv_stream(), &PipeT::UVAlloc, &PipeT::UVData);
-}
+ unsigned long const length = cmSystemTools::FileLength(filename);
+ cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
-void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::reset()
-{
- Process_ = nullptr;
- Target_ = nullptr;
- UVPipe_.reset();
- Buffer_.clear();
- Buffer_.shrink_to_fit();
-}
-
-void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::UVAlloc(uv_handle_t* handle,
- size_t suggestedSize,
- uv_buf_t* buf)
-{
- auto& pipe = *reinterpret_cast<PipeT*>(handle->data);
- pipe.Buffer_.resize(suggestedSize);
- buf->base = &pipe.Buffer_.front();
- buf->len = pipe.Buffer_.size();
-}
-
-void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::UVData(uv_stream_t* stream,
- ssize_t nread,
- const uv_buf_t* buf)
-{
- auto& pipe = *reinterpret_cast<PipeT*>(stream->data);
- if (nread > 0) {
- // Append data to merged output
- if ((buf->base != nullptr) && (pipe.Target_ != nullptr)) {
- pipe.Target_->append(buf->base, nread);
+ // Use lambda to save destructor calls of ifs
+ return [&ifs, length, &content, error]() -> bool {
+ if (!ifs) {
+ if (error != nullptr) {
+ *error = "Opening the file for reading failed.";
+ }
+ return false;
}
- } else if (nread < 0) {
- // EOF or error
- auto* proc = pipe.Process_;
- // Check it this an unusual error
- if (nread != UV_EOF) {
- if (!proc->Result()->error()) {
- proc->Result()->ErrorMessage =
- "libuv reading from pipe failed with error code ";
- proc->Result()->ErrorMessage += std::to_string(nread);
+ content.reserve(length);
+ typedef std::istreambuf_iterator<char> IsIt;
+ content.assign(IsIt{ ifs }, IsIt{});
+ if (!ifs) {
+ content.clear();
+ if (error != nullptr) {
+ *error = "Reading from the file failed.";
}
+ return false;
}
- // Clear libuv pipe handle and try to finish
- pipe.reset();
- proc->UVTryFinish();
- }
-}
-
-void cmQtAutoGenerator::ProcessResultT::reset()
-{
- ExitStatus = 0;
- TermSignal = 0;
- if (!StdOut.empty()) {
- StdOut.clear();
- StdOut.shrink_to_fit();
- }
- if (!StdErr.empty()) {
- StdErr.clear();
- StdErr.shrink_to_fit();
- }
- if (!ErrorMessage.empty()) {
- ErrorMessage.clear();
- ErrorMessage.shrink_to_fit();
- }
+ return true;
+ }();
}
-void cmQtAutoGenerator::ReadOnlyProcessT::setup(
- ProcessResultT* result, bool mergedOutput,
- std::vector<std::string> const& command, std::string const& workingDirectory)
+bool cmQtAutoGenerator::FileWrite(std::string const& filename,
+ std::string const& content,
+ std::string* error)
{
- Setup_.WorkingDirectory = workingDirectory;
- Setup_.Command = command;
- Setup_.Result = result;
- Setup_.MergedOutput = mergedOutput;
-}
-
-bool cmQtAutoGenerator::ReadOnlyProcessT::start(
- uv_loop_t* uv_loop, std::function<void()>&& finishedCallback)
-{
- if (IsStarted() || (Result() == nullptr)) {
- return false;
- }
-
- // Reset result before the start
- Result()->reset();
-
- // Fill command string pointers
- if (!Setup().Command.empty()) {
- CommandPtr_.reserve(Setup().Command.size() + 1);
- for (std::string const& arg : Setup().Command) {
- CommandPtr_.push_back(arg.c_str());
- }
- CommandPtr_.push_back(nullptr);
- } else {
- Result()->ErrorMessage = "Empty command";
- }
-
- if (!Result()->error()) {
- if (UVPipeOut_.init(uv_loop, this) != 0) {
- Result()->ErrorMessage = "libuv stdout pipe initialization failed";
- }
- }
- if (!Result()->error()) {
- if (UVPipeErr_.init(uv_loop, this) != 0) {
- Result()->ErrorMessage = "libuv stderr pipe initialization failed";
- }
- }
- if (!Result()->error()) {
- // -- Setup process stdio options
- // stdin
- UVOptionsStdIO_[0].flags = UV_IGNORE;
- UVOptionsStdIO_[0].data.stream = nullptr;
- // stdout
- UVOptionsStdIO_[1].flags =
- static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
- UVOptionsStdIO_[1].data.stream = UVPipeOut_.uv_stream();
- // stderr
- UVOptionsStdIO_[2].flags =
- static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
- UVOptionsStdIO_[2].data.stream = UVPipeErr_.uv_stream();
-
- // -- Setup process options
- std::fill_n(reinterpret_cast<char*>(&UVOptions_), sizeof(UVOptions_), 0);
- UVOptions_.exit_cb = &ReadOnlyProcessT::UVExit;
- UVOptions_.file = CommandPtr_[0];
- UVOptions_.args = const_cast<char**>(&CommandPtr_.front());
- UVOptions_.cwd = Setup_.WorkingDirectory.c_str();
- UVOptions_.flags = UV_PROCESS_WINDOWS_HIDE;
- UVOptions_.stdio_count = static_cast<int>(UVOptionsStdIO_.size());
- UVOptions_.stdio = &UVOptionsStdIO_.front();
-
- // -- Spawn process
- if (UVProcess_.spawn(*uv_loop, UVOptions_, this) != 0) {
- Result()->ErrorMessage = "libuv process spawn failed";
- }
- }
- // -- Start reading from stdio streams
- if (!Result()->error()) {
- if (UVPipeOut_.startRead(&Result()->StdOut) != 0) {
- Result()->ErrorMessage = "libuv start reading from stdout pipe failed";
- }
- }
- if (!Result()->error()) {
- if (UVPipeErr_.startRead(Setup_.MergedOutput ? &Result()->StdOut
- : &Result()->StdErr) != 0) {
- Result()->ErrorMessage = "libuv start reading from stderr pipe failed";
+ // Make sure the parent directory exists
+ if (!cmQtAutoGenerator::MakeParentDirectory(filename)) {
+ if (error != nullptr) {
+ *error = "Could not create parent directory.";
}
+ return false;
}
+ cmsys::ofstream ofs;
+ ofs.open(filename.c_str(),
+ (std::ios::out | std::ios::binary | std::ios::trunc));
- if (!Result()->error()) {
- IsStarted_ = true;
- FinishedCallback_ = std::move(finishedCallback);
- } else {
- // Clear libuv handles and finish
- UVProcess_.reset();
- UVPipeOut_.reset();
- UVPipeErr_.reset();
- CommandPtr_.clear();
- }
-
- return IsStarted();
-}
-
-void cmQtAutoGenerator::ReadOnlyProcessT::UVExit(uv_process_t* handle,
- int64_t exitStatus,
- int termSignal)
-{
- auto& proc = *reinterpret_cast<ReadOnlyProcessT*>(handle->data);
- if (proc.IsStarted() && !proc.IsFinished()) {
- // Set error message on demand
- proc.Result()->ExitStatus = exitStatus;
- proc.Result()->TermSignal = termSignal;
- if (!proc.Result()->error()) {
- if (termSignal != 0) {
- proc.Result()->ErrorMessage = "Process was terminated by signal ";
- proc.Result()->ErrorMessage +=
- std::to_string(proc.Result()->TermSignal);
- } else if (exitStatus != 0) {
- proc.Result()->ErrorMessage = "Process failed with return value ";
- proc.Result()->ErrorMessage +=
- std::to_string(proc.Result()->ExitStatus);
+ // Use lambda to save destructor calls of ofs
+ return [&ofs, &content, error]() -> bool {
+ if (!ofs) {
+ if (error != nullptr) {
+ *error = "Opening file for writing failed.";
}
+ return false;
}
-
- // Reset process handle and try to finish
- proc.UVProcess_.reset();
- proc.UVTryFinish();
- }
-}
-
-void cmQtAutoGenerator::ReadOnlyProcessT::UVTryFinish()
-{
- // There still might be data in the pipes after the process has finished.
- // Therefore check if the process is finished AND all pipes are closed
- // before signaling the worker thread to continue.
- if (UVProcess_.get() == nullptr) {
- if (UVPipeOut_.uv_pipe() == nullptr) {
- if (UVPipeErr_.uv_pipe() == nullptr) {
- IsFinished_ = true;
- FinishedCallback_();
+ ofs << content;
+ if (!ofs.good()) {
+ if (error != nullptr) {
+ *error = "File writing failed.";
}
+ return false;
}
- }
+ return true;
+ }();
}
-cmQtAutoGenerator::cmQtAutoGenerator()
- : FileSys_(&Logger_)
+bool cmQtAutoGenerator::FileDiffers(std::string const& filename,
+ std::string const& content)
{
- // Initialize logger
- {
- std::string verbose;
- if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) {
- unsigned long iVerbose = 0;
- if (cmSystemTools::StringToULong(verbose.c_str(), &iVerbose)) {
- Logger_.SetVerbosity(static_cast<unsigned int>(iVerbose));
- } else {
- // Non numeric verbosity
- Logger_.SetVerbose(cmSystemTools::IsOn(verbose));
- }
- }
- }
- {
- std::string colorEnv;
- cmSystemTools::GetEnv("COLOR", colorEnv);
- if (!colorEnv.empty()) {
- Logger_.SetColorOutput(cmSystemTools::IsOn(colorEnv));
- } else {
- Logger_.SetColorOutput(true);
- }
+ bool differs = true;
+ std::string oldContents;
+ if (FileRead(oldContents, filename) && (oldContents == content)) {
+ differs = false;
}
-
- // Initialize libuv loop
- uv_disable_stdio_inheritance();
-#ifdef CMAKE_UV_SIGNAL_HACK
- UVHackRAII_ = cm::make_unique<cmUVSignalHackRAII>();
-#endif
- UVLoop_ = cm::make_unique<uv_loop_t>();
- uv_loop_init(UVLoop());
+ return differs;
}
-cmQtAutoGenerator::~cmQtAutoGenerator()
-{
- // Close libuv loop
- uv_loop_close(UVLoop());
-}
+cmQtAutoGenerator::cmQtAutoGenerator() = default;
+
+cmQtAutoGenerator::~cmQtAutoGenerator() = default;
bool cmQtAutoGenerator::Run(std::string const& infoFile,
std::string const& config)
@@ -682,6 +278,13 @@ bool cmQtAutoGenerator::Run(std::string const& infoFile,
// Info settings
InfoFile_ = infoFile;
cmSystemTools::ConvertToUnixSlashes(InfoFile_);
+ if (!InfoFileTime_.Load(InfoFile_)) {
+ std::string msg = "AutoGen: The info file ";
+ msg += Quoted(InfoFile_);
+ msg += " is not readable\n";
+ cmSystemTools::Stderr(msg);
+ return false;
+ }
InfoDir_ = cmSystemTools::GetFilenamePath(infoFile);
InfoConfig_ = config;
diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h
index 9956a99a3..ff4c4c942 100644
--- a/Source/cmQtAutoGenerator.h
+++ b/Source/cmQtAutoGenerator.h
@@ -5,239 +5,73 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include "cmFilePathChecksum.h"
+#include "cmFileTime.h"
#include "cmQtAutoGen.h"
-#include "cmUVHandlePtr.h"
-#include "cmUVSignalHackRAII.h" // IWYU pragma: keep
-#include "cm_uv.h"
-#include <array>
-#include <functional>
#include <mutex>
-#include <stddef.h>
-#include <stdint.h>
#include <string>
#include <vector>
class cmMakefile;
-/// @brief Base class for QtAutoGen gernerators
+/** \class cmQtAutoGenerator
+ * \brief Base class for QtAutoGen generators
+ */
class cmQtAutoGenerator : public cmQtAutoGen
{
public:
// -- Types
- /// @brief Thread safe logging
+ /**
+ * Thread safe logger
+ */
class Logger
{
public:
+ // -- Construction
+ Logger();
+ ~Logger();
// -- Verbosity
unsigned int Verbosity() const { return this->Verbosity_; }
void SetVerbosity(unsigned int value) { this->Verbosity_ = value; }
void RaiseVerbosity(std::string const& value);
bool Verbose() const { return (this->Verbosity_ != 0); }
void SetVerbose(bool value) { this->Verbosity_ = value ? 1 : 0; }
+ // -- Color output
bool ColorOutput() const { return this->ColorOutput_; }
void SetColorOutput(bool value);
// -- Log info
- void Info(GeneratorT genType, std::string const& message);
+ void Info(GenT genType, std::string const& message) const;
// -- Log warning
- void Warning(GeneratorT genType, std::string const& message);
- void WarningFile(GeneratorT genType, std::string const& filename,
- std::string const& message);
+ void Warning(GenT genType, std::string const& message) const;
+ void WarningFile(GenT genType, std::string const& filename,
+ std::string const& message) const;
// -- Log error
- void Error(GeneratorT genType, std::string const& message);
- void ErrorFile(GeneratorT genType, std::string const& filename,
- std::string const& message);
- void ErrorCommand(GeneratorT genType, std::string const& message,
+ void Error(GenT genType, std::string const& message) const;
+ void ErrorFile(GenT genType, std::string const& filename,
+ std::string const& message) const;
+ void ErrorCommand(GenT genType, std::string const& message,
std::vector<std::string> const& command,
- std::string const& output);
+ std::string const& output) const;
private:
static std::string HeadLine(std::string const& title);
private:
- std::mutex Mutex_;
+ mutable std::mutex Mutex_;
unsigned int Verbosity_ = 0;
bool ColorOutput_ = false;
};
- /// @brief Thread safe file system interface
- class FileSystem
- {
- public:
- FileSystem(Logger* log)
- : Log_(log)
- {
- }
-
- /// @brief Logger
- Logger* Log() const { return Log_; }
-
- // -- Paths
- /// @brief Wrapper for cmSystemTools::GetRealPath
- std::string GetRealPath(std::string const& filename);
- /// @brief Wrapper for cmSystemTools::CollapseCombinedPath
- std::string CollapseCombinedPath(std::string const& dir,
- std::string const& file);
- /// @brief Wrapper for cmSystemTools::SplitPath
- void SplitPath(const std::string& p, std::vector<std::string>& components,
- bool expand_home_dir = true);
- /// @brief Wrapper for cmSystemTools::JoinPath
- std::string JoinPath(const std::vector<std::string>& components);
- /// @brief Wrapper for cmSystemTools::JoinPath
- std::string JoinPath(std::vector<std::string>::const_iterator first,
- std::vector<std::string>::const_iterator last);
- /// @brief Wrapper for cmSystemTools::GetFilenameWithoutLastExtension
- std::string GetFilenameWithoutLastExtension(const std::string& filename);
- /// @brief Wrapper for cmQtAutoGen::SubDirPrefix
- std::string SubDirPrefix(std::string const& filename);
- /// @brief Wrapper for cmFilePathChecksum::setupParentDirs
- void setupFilePathChecksum(std::string const& currentSrcDir,
- std::string const& currentBinDir,
- std::string const& projectSrcDir,
- std::string const& projectBinDir);
- /// @brief Wrapper for cmFilePathChecksum::getPart
- std::string GetFilePathChecksum(std::string const& filename);
-
- // -- File access
- /// @brief Wrapper for cmSystemTools::FileExists
- bool FileExists(std::string const& filename);
- /// @brief Wrapper for cmSystemTools::FileExists
- bool FileExists(std::string const& filename, bool isFile);
- /// @brief Wrapper for cmSystemTools::FileLength
- unsigned long FileLength(std::string const& filename);
- bool FileIsOlderThan(std::string const& buildFile,
- std::string const& sourceFile,
- std::string* error = nullptr);
-
- bool FileRead(std::string& content, std::string const& filename,
- std::string* error = nullptr);
- /// @brief Error logging version
- bool FileRead(GeneratorT genType, std::string& content,
- std::string const& filename);
-
- bool FileWrite(std::string const& filename, std::string const& content,
- std::string* error = nullptr);
- /// @brief Error logging version
- bool FileWrite(GeneratorT genType, std::string const& filename,
- std::string const& content);
-
- bool FileDiffers(std::string const& filename, std::string const& content);
-
- bool FileRemove(std::string const& filename);
- bool Touch(std::string const& filename, bool create = false);
-
- // -- Directory access
- bool MakeDirectory(std::string const& dirname);
- /// @brief Error logging version
- bool MakeDirectory(GeneratorT genType, std::string const& dirname);
-
- bool MakeParentDirectory(std::string const& filename);
- /// @brief Error logging version
- bool MakeParentDirectory(GeneratorT genType, std::string const& filename);
-
- private:
- std::mutex Mutex_;
- cmFilePathChecksum FilePathChecksum_;
- Logger* Log_;
- };
-
- /// @brief Return value and output of an external process
- struct ProcessResultT
- {
- void reset();
- bool error() const
- {
- return (ExitStatus != 0) || (TermSignal != 0) || !ErrorMessage.empty();
- }
-
- std::int64_t ExitStatus = 0;
- int TermSignal = 0;
- std::string StdOut;
- std::string StdErr;
- std::string ErrorMessage;
- };
-
- /// @brief External process management class
- struct ReadOnlyProcessT
- {
- // -- Types
-
- /// @brief libuv pipe buffer class
- class PipeT
- {
- public:
- int init(uv_loop_t* uv_loop, ReadOnlyProcessT* process);
- int startRead(std::string* target);
- void reset();
-
- // -- Libuv casts
- uv_pipe_t* uv_pipe() { return UVPipe_.get(); }
- uv_stream_t* uv_stream()
- {
- return reinterpret_cast<uv_stream_t*>(uv_pipe());
- }
- uv_handle_t* uv_handle()
- {
- return reinterpret_cast<uv_handle_t*>(uv_pipe());
- }
-
- // -- Libuv callbacks
- static void UVAlloc(uv_handle_t* handle, size_t suggestedSize,
- uv_buf_t* buf);
- static void UVData(uv_stream_t* stream, ssize_t nread,
- const uv_buf_t* buf);
-
- private:
- ReadOnlyProcessT* Process_ = nullptr;
- std::string* Target_ = nullptr;
- std::vector<char> Buffer_;
- cm::uv_pipe_ptr UVPipe_;
- };
-
- /// @brief Process settings
- struct SetupT
- {
- std::string WorkingDirectory;
- std::vector<std::string> Command;
- ProcessResultT* Result = nullptr;
- bool MergedOutput = false;
- };
-
- // -- Const accessors
- const SetupT& Setup() const { return Setup_; }
- ProcessResultT* Result() const { return Setup_.Result; }
- bool IsStarted() const { return IsStarted_; }
- bool IsFinished() const { return IsFinished_; }
-
- // -- Runtime
- void setup(ProcessResultT* result, bool mergedOutput,
- std::vector<std::string> const& command,
- std::string const& workingDirectory = std::string());
- bool start(uv_loop_t* uv_loop, std::function<void()>&& finishedCallback);
-
- private:
- // -- Friends
- friend class PipeT;
- // -- Libuv callbacks
- static void UVExit(uv_process_t* handle, int64_t exitStatus,
- int termSignal);
- void UVTryFinish();
-
- // -- Setup
- SetupT Setup_;
- // -- Runtime
- bool IsStarted_ = false;
- bool IsFinished_ = false;
- std::function<void()> FinishedCallback_;
- std::vector<const char*> CommandPtr_;
- std::array<uv_stdio_container_t, 3> UVOptionsStdIO_;
- uv_process_options_t UVOptions_;
- cm::uv_process_ptr UVProcess_;
- PipeT UVPipeOut_;
- PipeT UVPipeErr_;
- };
+ // -- File system methods
+ static bool MakeParentDirectory(std::string const& filename);
+ static bool FileRead(std::string& content, std::string const& filename,
+ std::string* error = nullptr);
+ static bool FileWrite(std::string const& filename,
+ std::string const& content,
+ std::string* error = nullptr);
+ static bool FileDiffers(std::string const& filename,
+ std::string const& content);
public:
// -- Constructors
@@ -250,18 +84,11 @@ public:
// -- Run
bool Run(std::string const& infoFile, std::string const& config);
- // -- Accessors
- // Logging
- Logger& Log() { return Logger_; }
- // File System
- FileSystem& FileSys() { return FileSys_; }
- // InfoFile
+ // -- InfoFile
std::string const& InfoFile() const { return InfoFile_; }
+ cmFileTime const& InfoFileTime() const { return InfoFileTime_; }
std::string const& InfoDir() const { return InfoDir_; }
std::string const& InfoConfig() const { return InfoConfig_; }
- // libuv loop
- uv_loop_t* UVLoop() { return UVLoop_.get(); }
- cm::uv_async_ptr& UVRequest() { return UVRequest_; }
// -- Utility
static std::string SettingsFind(std::string const& content, const char* key);
@@ -272,19 +99,11 @@ protected:
virtual bool Process() = 0;
private:
- // -- Logging
- Logger Logger_;
- FileSystem FileSys_;
// -- Info settings
std::string InfoFile_;
+ cmFileTime InfoFileTime_;
std::string InfoDir_;
std::string InfoConfig_;
-// -- libuv loop
-#ifdef CMAKE_UV_SIGNAL_HACK
- std::unique_ptr<cmUVSignalHackRAII> UVHackRAII_;
-#endif
- std::unique_ptr<uv_loop_t> UVLoop_;
- cm::uv_async_ptr UVRequest_;
};
#endif
diff --git a/Source/cmQtAutoGeneratorMocUic.cxx b/Source/cmQtAutoGeneratorMocUic.cxx
deleted file mode 100644
index ddff4cf87..000000000
--- a/Source/cmQtAutoGeneratorMocUic.cxx
+++ /dev/null
@@ -1,2042 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmQtAutoGeneratorMocUic.h"
-
-#include <algorithm>
-#include <array>
-#include <cstddef>
-#include <functional>
-#include <list>
-#include <memory>
-#include <set>
-#include <sstream>
-#include <utility>
-
-#include "cmAlgorithms.h"
-#include "cmCryptoHash.h"
-#include "cmMakefile.h"
-#include "cmQtAutoGen.h"
-#include "cmSystemTools.h"
-#include "cmake.h"
-
-#if defined(__APPLE__)
-# include <unistd.h>
-#endif
-
-// -- Class methods
-
-std::string cmQtAutoGeneratorMocUic::BaseSettingsT::AbsoluteBuildPath(
- std::string const& relativePath) const
-{
- return FileSys->CollapseCombinedPath(AutogenBuildDir, relativePath);
-}
-
-/**
- * @brief Tries to find the header file to the given file base path by
- * appending different header extensions
- * @return True on success
- */
-bool cmQtAutoGeneratorMocUic::BaseSettingsT::FindHeader(
- std::string& header, std::string const& testBasePath) const
-{
- for (std::string const& ext : HeaderExtensions) {
- std::string testFilePath(testBasePath);
- testFilePath.push_back('.');
- testFilePath += ext;
- if (FileSys->FileExists(testFilePath)) {
- header = testFilePath;
- return true;
- }
- }
- return false;
-}
-
-bool cmQtAutoGeneratorMocUic::MocSettingsT::skipped(
- std::string const& fileName) const
-{
- return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
-}
-
-/**
- * @brief Returns the first relevant Qt macro name found in the given C++ code
- * @return The name of the Qt macro or an empty string
- */
-std::string cmQtAutoGeneratorMocUic::MocSettingsT::FindMacro(
- std::string const& content) const
-{
- for (KeyExpT const& filter : MacroFilters) {
- // Run a simple find string operation before the expensive
- // regular expression check
- if (content.find(filter.Key) != std::string::npos) {
- cmsys::RegularExpressionMatch match;
- if (filter.Exp.find(content.c_str(), match)) {
- // Return macro name on demand
- return filter.Key;
- }
- }
- }
- return std::string();
-}
-
-std::string cmQtAutoGeneratorMocUic::MocSettingsT::MacrosString() const
-{
- std::string res;
- const auto itB = MacroFilters.cbegin();
- const auto itE = MacroFilters.cend();
- const auto itL = itE - 1;
- auto itC = itB;
- for (; itC != itE; ++itC) {
- // Separator
- if (itC != itB) {
- if (itC != itL) {
- res += ", ";
- } else {
- res += " or ";
- }
- }
- // Key
- res += itC->Key;
- }
- return res;
-}
-
-std::string cmQtAutoGeneratorMocUic::MocSettingsT::FindIncludedFile(
- std::string const& sourcePath, std::string const& includeString) const
-{
- // Search in vicinity of the source
- {
- std::string testPath = sourcePath;
- testPath += includeString;
- if (FileSys->FileExists(testPath)) {
- return FileSys->GetRealPath(testPath);
- }
- }
- // Search in include directories
- for (std::string const& path : IncludePaths) {
- std::string fullPath = path;
- fullPath.push_back('/');
- fullPath += includeString;
- if (FileSys->FileExists(fullPath)) {
- return FileSys->GetRealPath(fullPath);
- }
- }
- // Return empty string
- return std::string();
-}
-
-void cmQtAutoGeneratorMocUic::MocSettingsT::FindDependencies(
- std::string const& content, std::set<std::string>& depends) const
-{
- if (!DependFilters.empty() && !content.empty()) {
- for (KeyExpT const& filter : DependFilters) {
- // Run a simple find string check
- if (content.find(filter.Key) != std::string::npos) {
- // Run the expensive regular expression check loop
- const char* contentChars = content.c_str();
- cmsys::RegularExpressionMatch match;
- while (filter.Exp.find(contentChars, match)) {
- {
- std::string dep = match.match(1);
- if (!dep.empty()) {
- depends.emplace(std::move(dep));
- }
- }
- contentChars += match.end();
- }
- }
- }
- }
-}
-
-bool cmQtAutoGeneratorMocUic::UicSettingsT::skipped(
- std::string const& fileName) const
-{
- return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
-}
-
-void cmQtAutoGeneratorMocUic::JobParseT::Process(WorkerT& wrk)
-{
- if (AutoMoc && Header) {
- // Don't parse header for moc if the file is included by a source already
- if (wrk.Gen().ParallelMocIncluded(FileName)) {
- AutoMoc = false;
- }
- }
-
- if (AutoMoc || AutoUic) {
- std::string error;
- MetaT meta;
- if (wrk.FileSys().FileRead(meta.Content, FileName, &error)) {
- if (!meta.Content.empty()) {
- meta.FileDir = wrk.FileSys().SubDirPrefix(FileName);
- meta.FileBase =
- wrk.FileSys().GetFilenameWithoutLastExtension(FileName);
-
- bool success = true;
- if (AutoMoc) {
- if (Header) {
- success = ParseMocHeader(wrk, meta);
- } else {
- success = ParseMocSource(wrk, meta);
- }
- }
- if (AutoUic && success) {
- ParseUic(wrk, meta);
- }
- } else {
- wrk.LogFileWarning(GeneratorT::GEN, FileName,
- "The source file is empty");
- }
- } else {
- wrk.LogFileError(GeneratorT::GEN, FileName,
- "Could not read the file: " + error);
- }
- }
-}
-
-bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocSource(WorkerT& wrk,
- MetaT const& meta)
-{
- struct JobPre
- {
- bool self; // source file is self
- bool underscore; // "moc_" style include
- std::string SourceFile;
- std::string IncludeString;
- };
-
- struct MocInclude
- {
- std::string Inc; // full include string
- std::string Dir; // include string directory
- std::string Base; // include string file base
- };
-
- // Check if this source file contains a relevant macro
- std::string const ownMacro = wrk.Moc().FindMacro(meta.Content);
-
- // Extract moc includes from file
- std::deque<MocInclude> mocIncsUsc;
- std::deque<MocInclude> mocIncsDot;
- {
- if (meta.Content.find("moc") != std::string::npos) {
- const char* contentChars = meta.Content.c_str();
- cmsys::RegularExpressionMatch match;
- while (wrk.Moc().RegExpInclude.find(contentChars, match)) {
- std::string incString = match.match(2);
- std::string incDir(wrk.FileSys().SubDirPrefix(incString));
- std::string incBase =
- wrk.FileSys().GetFilenameWithoutLastExtension(incString);
- if (cmHasLiteralPrefix(incBase, "moc_")) {
- // moc_<BASE>.cxx
- // Remove the moc_ part from the base name
- mocIncsUsc.emplace_back(MocInclude{
- std::move(incString), std::move(incDir), incBase.substr(4) });
- } else {
- // <BASE>.moc
- mocIncsDot.emplace_back(MocInclude{
- std::move(incString), std::move(incDir), std::move(incBase) });
- }
- // Forward content pointer
- contentChars += match.end();
- }
- }
- }
-
- // Check if there is anything to do
- if (ownMacro.empty() && mocIncsUsc.empty() && mocIncsDot.empty()) {
- return true;
- }
-
- bool ownDotMocIncluded = false;
- bool ownMocUscIncluded = false;
- std::deque<JobPre> jobs;
-
- // Process moc_<BASE>.cxx includes
- for (const MocInclude& mocInc : mocIncsUsc) {
- std::string const header =
- MocFindIncludedHeader(wrk, meta.FileDir, mocInc.Dir + mocInc.Base);
- if (!header.empty()) {
- // Check if header is skipped
- if (wrk.Moc().skipped(header)) {
- continue;
- }
- // Register moc job
- const bool ownMoc = (mocInc.Base == meta.FileBase);
- jobs.emplace_back(JobPre{ ownMoc, true, header, mocInc.Inc });
- // Store meta information for relaxed mode
- if (ownMoc) {
- ownMocUscIncluded = true;
- }
- } else {
- {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", but the header ";
- emsg += Quoted(MocStringHeaders(wrk, mocInc.Base));
- emsg += " could not be found.";
- wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
- }
- return false;
- }
- }
-
- // Process <BASE>.moc includes
- for (const MocInclude& mocInc : mocIncsDot) {
- const bool ownMoc = (mocInc.Base == meta.FileBase);
- if (wrk.Moc().RelaxedMode) {
- // Relaxed mode
- if (!ownMacro.empty() && ownMoc) {
- // Add self
- jobs.emplace_back(JobPre{ ownMoc, false, FileName, mocInc.Inc });
- ownDotMocIncluded = true;
- } else {
- // In relaxed mode try to find a header instead but issue a warning.
- // This is for KDE4 compatibility
- std::string const header =
- MocFindIncludedHeader(wrk, meta.FileDir, mocInc.Dir + mocInc.Base);
- if (!header.empty()) {
- // Check if header is skipped
- if (wrk.Moc().skipped(header)) {
- continue;
- }
- // Register moc job
- jobs.emplace_back(JobPre{ ownMoc, false, header, mocInc.Inc });
- if (ownMacro.empty()) {
- if (ownMoc) {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", but does not contain a ";
- emsg += wrk.Moc().MacrosString();
- emsg += " macro.\nRunning moc on\n ";
- emsg += Quoted(header);
- emsg += "!\nBetter include ";
- emsg += Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += " for a compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
- wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
- } else {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += " instead of ";
- emsg += Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += ".\nRunning moc on\n ";
- emsg += Quoted(header);
- emsg += "!\nBetter include ";
- emsg += Quoted("moc_" + mocInc.Base + ".cpp");
- emsg += " for compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n";
- wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
- }
- }
- } else {
- {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", which seems to be the moc file from a different "
- "source file.\nCMAKE_AUTOMOC_RELAXED_MODE: Also a "
- "matching header ";
- emsg += Quoted(MocStringHeaders(wrk, mocInc.Base));
- emsg += " could not be found.";
- wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
- }
- return false;
- }
- }
- } else {
- // Strict mode
- if (ownMoc) {
- // Include self
- jobs.emplace_back(JobPre{ ownMoc, false, FileName, mocInc.Inc });
- ownDotMocIncluded = true;
- // Accept but issue a warning if moc isn't required
- if (ownMacro.empty()) {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", but does not contain a ";
- emsg += wrk.Moc().MacrosString();
- emsg += " macro.";
- wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
- }
- } else {
- // Don't allow <BASE>.moc include other than self in strict mode
- {
- std::string emsg = "The file includes the moc file ";
- emsg += Quoted(mocInc.Inc);
- emsg += ", which seems to be the moc file from a different "
- "source file.\nThis is not supported. Include ";
- emsg += Quoted(meta.FileBase + ".moc");
- emsg += " to run moc on this source file.";
- wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
- }
- return false;
- }
- }
- }
-
- if (!ownMacro.empty() && !ownDotMocIncluded) {
- // In this case, check whether the scanned file itself contains a
- // Q_OBJECT.
- // If this is the case, the moc_foo.cpp should probably be generated from
- // foo.cpp instead of foo.h, because otherwise it won't build.
- // But warn, since this is not how it is supposed to be used.
- // This is for KDE4 compatibility.
- if (wrk.Moc().RelaxedMode && ownMocUscIncluded) {
- JobPre uscJobPre;
- // Remove underscore job request
- {
- auto itC = jobs.begin();
- auto itE = jobs.end();
- for (; itC != itE; ++itC) {
- JobPre& job(*itC);
- if (job.self && job.underscore) {
- uscJobPre = std::move(job);
- jobs.erase(itC);
- break;
- }
- }
- }
- // Issue a warning
- {
- std::string emsg = "The file contains a ";
- emsg += ownMacro;
- emsg += " macro, but does not include ";
- emsg += Quoted(meta.FileBase + ".moc");
- emsg += ". Instead it includes ";
- emsg += Quoted(uscJobPre.IncludeString);
- emsg += ".\nRunning moc on\n ";
- emsg += Quoted(FileName);
- emsg += "!\nBetter include ";
- emsg += Quoted(meta.FileBase + ".moc");
- emsg += " for compatibility with strict mode.\n"
- "(CMAKE_AUTOMOC_RELAXED_MODE warning)";
- wrk.LogFileWarning(GeneratorT::MOC, FileName, emsg);
- }
- // Add own source job
- jobs.emplace_back(
- JobPre{ true, false, FileName, uscJobPre.IncludeString });
- } else {
- // Otherwise always error out since it will not compile.
- {
- std::string emsg = "The file contains a ";
- emsg += ownMacro;
- emsg += " macro, but does not include ";
- emsg += Quoted(meta.FileBase + ".moc");
- emsg += "!\nConsider to\n - add #include \"";
- emsg += meta.FileBase;
- emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file";
- wrk.LogFileError(GeneratorT::MOC, FileName, emsg);
- }
- return false;
- }
- }
-
- // Convert pre jobs to actual jobs
- for (JobPre& jobPre : jobs) {
- JobHandleT jobHandle(new JobMocT(std::move(jobPre.SourceFile), FileName,
- std::move(jobPre.IncludeString)));
- if (jobPre.self) {
- // Read dependencies from this source
- static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content);
- }
- if (!wrk.Gen().ParallelJobPushMoc(jobHandle)) {
- return false;
- }
- }
- return true;
-}
-
-bool cmQtAutoGeneratorMocUic::JobParseT::ParseMocHeader(WorkerT& wrk,
- MetaT const& meta)
-{
- bool success = true;
- std::string const macroName = wrk.Moc().FindMacro(meta.Content);
- if (!macroName.empty()) {
- JobHandleT jobHandle(
- new JobMocT(std::string(FileName), std::string(), std::string()));
- // Read dependencies from this source
- static_cast<JobMocT&>(*jobHandle).FindDependencies(wrk, meta.Content);
- success = wrk.Gen().ParallelJobPushMoc(jobHandle);
- }
- return success;
-}
-
-std::string cmQtAutoGeneratorMocUic::JobParseT::MocStringHeaders(
- WorkerT& wrk, std::string const& fileBase) const
-{
- std::string res = fileBase;
- res += ".{";
- res += cmJoin(wrk.Base().HeaderExtensions, ",");
- res += "}";
- return res;
-}
-
-std::string cmQtAutoGeneratorMocUic::JobParseT::MocFindIncludedHeader(
- WorkerT& wrk, std::string const& includerDir, std::string const& includeBase)
-{
- std::string header;
- // Search in vicinity of the source
- if (!wrk.Base().FindHeader(header, includerDir + includeBase)) {
- // Search in include directories
- for (std::string const& path : wrk.Moc().IncludePaths) {
- std::string fullPath = path;
- fullPath.push_back('/');
- fullPath += includeBase;
- if (wrk.Base().FindHeader(header, fullPath)) {
- break;
- }
- }
- }
- // Sanitize
- if (!header.empty()) {
- header = wrk.FileSys().GetRealPath(header);
- }
- return header;
-}
-
-bool cmQtAutoGeneratorMocUic::JobParseT::ParseUic(WorkerT& wrk,
- MetaT const& meta)
-{
- bool success = true;
- if (meta.Content.find("ui_") != std::string::npos) {
- const char* contentChars = meta.Content.c_str();
- cmsys::RegularExpressionMatch match;
- while (wrk.Uic().RegExpInclude.find(contentChars, match)) {
- if (!ParseUicInclude(wrk, meta, match.match(2))) {
- success = false;
- break;
- }
- contentChars += match.end();
- }
- }
- return success;
-}
-
-bool cmQtAutoGeneratorMocUic::JobParseT::ParseUicInclude(
- WorkerT& wrk, MetaT const& meta, std::string&& includeString)
-{
- bool success = false;
- std::string uiInputFile = UicFindIncludedFile(wrk, meta, includeString);
- if (!uiInputFile.empty()) {
- if (!wrk.Uic().skipped(uiInputFile)) {
- JobHandleT jobHandle(new JobUicT(std::move(uiInputFile), FileName,
- std::move(includeString)));
- success = wrk.Gen().ParallelJobPushUic(jobHandle);
- } else {
- // A skipped file is successful
- success = true;
- }
- }
- return success;
-}
-
-std::string cmQtAutoGeneratorMocUic::JobParseT::UicFindIncludedFile(
- WorkerT& wrk, MetaT const& meta, std::string const& includeString)
-{
- std::string res;
- std::string searchFile =
- wrk.FileSys().GetFilenameWithoutLastExtension(includeString).substr(3);
- searchFile += ".ui";
- // Collect search paths list
- std::deque<std::string> testFiles;
- {
- std::string const searchPath = wrk.FileSys().SubDirPrefix(includeString);
-
- std::string searchFileFull;
- if (!searchPath.empty()) {
- searchFileFull = searchPath;
- searchFileFull += searchFile;
- }
- // Vicinity of the source
- {
- std::string const sourcePath = meta.FileDir;
- testFiles.push_back(sourcePath + searchFile);
- if (!searchPath.empty()) {
- testFiles.push_back(sourcePath + searchFileFull);
- }
- }
- // AUTOUIC search paths
- if (!wrk.Uic().SearchPaths.empty()) {
- for (std::string const& sPath : wrk.Uic().SearchPaths) {
- testFiles.push_back((sPath + "/").append(searchFile));
- }
- if (!searchPath.empty()) {
- for (std::string const& sPath : wrk.Uic().SearchPaths) {
- testFiles.push_back((sPath + "/").append(searchFileFull));
- }
- }
- }
- }
-
- // Search for the .ui file!
- for (std::string const& testFile : testFiles) {
- if (wrk.FileSys().FileExists(testFile)) {
- res = wrk.FileSys().GetRealPath(testFile);
- break;
- }
- }
-
- // Log error
- if (res.empty()) {
- std::string emsg = "Could not find ";
- emsg += Quoted(searchFile);
- emsg += " in\n";
- for (std::string const& testFile : testFiles) {
- emsg += " ";
- emsg += Quoted(testFile);
- emsg += "\n";
- }
- wrk.LogFileError(GeneratorT::UIC, FileName, emsg);
- }
-
- return res;
-}
-
-void cmQtAutoGeneratorMocUic::JobMocPredefsT::Process(WorkerT& wrk)
-{
- // (Re)generate moc_predefs.h on demand
- bool generate(false);
- bool fileExists(wrk.FileSys().FileExists(wrk.Moc().PredefsFileAbs));
- if (!fileExists) {
- if (wrk.Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(wrk.Moc().PredefsFileRel);
- reason += " because it doesn't exist";
- wrk.LogInfo(GeneratorT::MOC, reason);
- }
- generate = true;
- } else if (wrk.Moc().SettingsChanged) {
- if (wrk.Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(wrk.Moc().PredefsFileRel);
- reason += " because the settings changed.";
- wrk.LogInfo(GeneratorT::MOC, reason);
- }
- generate = true;
- }
- if (generate) {
- ProcessResultT result;
- {
- // Compose command
- std::vector<std::string> cmd = wrk.Moc().PredefsCmd;
- // Add includes
- cmd.insert(cmd.end(), wrk.Moc().Includes.begin(),
- wrk.Moc().Includes.end());
- // Add definitions
- for (std::string const& def : wrk.Moc().Definitions) {
- cmd.push_back("-D" + def);
- }
- // Execute command
- if (!wrk.RunProcess(GeneratorT::MOC, result, cmd)) {
- std::string emsg = "The content generation command for ";
- emsg += Quoted(wrk.Moc().PredefsFileRel);
- emsg += " failed.\n";
- emsg += result.ErrorMessage;
- wrk.LogCommandError(GeneratorT::MOC, emsg, cmd, result.StdOut);
- }
- }
-
- // (Re)write predefs file only on demand
- if (!result.error()) {
- if (!fileExists ||
- wrk.FileSys().FileDiffers(wrk.Moc().PredefsFileAbs, result.StdOut)) {
- if (wrk.FileSys().FileWrite(GeneratorT::MOC, wrk.Moc().PredefsFileAbs,
- result.StdOut)) {
- // Success
- } else {
- std::string emsg = "Writing ";
- emsg += Quoted(wrk.Moc().PredefsFileRel);
- emsg += " failed.";
- wrk.LogFileError(GeneratorT::MOC, wrk.Moc().PredefsFileAbs, emsg);
- }
- } else {
- // Touch to update the time stamp
- if (wrk.Log().Verbose()) {
- std::string msg = "Touching ";
- msg += Quoted(wrk.Moc().PredefsFileRel);
- msg += ".";
- wrk.LogInfo(GeneratorT::MOC, msg);
- }
- wrk.FileSys().Touch(wrk.Moc().PredefsFileAbs);
- }
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::JobMocT::FindDependencies(
- WorkerT& wrk, std::string const& content)
-{
- wrk.Moc().FindDependencies(content, Depends);
- DependsValid = true;
-}
-
-void cmQtAutoGeneratorMocUic::JobMocT::Process(WorkerT& wrk)
-{
- // Compute build file name
- if (!IncludeString.empty()) {
- BuildFile = wrk.Base().AutogenIncludeDir;
- BuildFile += '/';
- BuildFile += IncludeString;
- } else {
- // Relative build path
- std::string relPath = wrk.FileSys().GetFilePathChecksum(SourceFile);
- relPath += "/moc_";
- relPath += wrk.FileSys().GetFilenameWithoutLastExtension(SourceFile);
-
- // Register relative file path with duplication check
- relPath = wrk.Gen().ParallelMocAutoRegister(relPath);
-
- // Absolute build path
- if (wrk.Base().MultiConfig) {
- BuildFile = wrk.Base().AutogenIncludeDir;
- BuildFile += '/';
- BuildFile += relPath;
- } else {
- BuildFile = wrk.Base().AbsoluteBuildPath(relPath);
- }
- }
-
- if (UpdateRequired(wrk)) {
- GenerateMoc(wrk);
- }
-}
-
-bool cmQtAutoGeneratorMocUic::JobMocT::UpdateRequired(WorkerT& wrk)
-{
- bool const verbose = wrk.Gen().Log().Verbose();
-
- // Test if the build file exists
- if (!wrk.FileSys().FileExists(BuildFile)) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from its source file ";
- reason += Quoted(SourceFile);
- reason += " because it doesn't exist";
- wrk.LogInfo(GeneratorT::MOC, reason);
- }
- return true;
- }
-
- // Test if any setting changed
- if (wrk.Moc().SettingsChanged) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from ";
- reason += Quoted(SourceFile);
- reason += " because the MOC settings changed";
- wrk.LogInfo(GeneratorT::MOC, reason);
- }
- return true;
- }
-
- // Test if the moc_predefs file is newer
- if (!wrk.Moc().PredefsFileAbs.empty()) {
- bool isOlder = false;
- {
- std::string error;
- isOlder = wrk.FileSys().FileIsOlderThan(
- BuildFile, wrk.Moc().PredefsFileAbs, &error);
- if (!isOlder && !error.empty()) {
- wrk.LogError(GeneratorT::MOC, error);
- return false;
- }
- }
- if (isOlder) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " because it's older than: ";
- reason += Quoted(wrk.Moc().PredefsFileAbs);
- wrk.LogInfo(GeneratorT::MOC, reason);
- }
- return true;
- }
- }
-
- // Test if the source file is newer
- {
- bool isOlder = false;
- {
- std::string error;
- isOlder = wrk.FileSys().FileIsOlderThan(BuildFile, SourceFile, &error);
- if (!isOlder && !error.empty()) {
- wrk.LogError(GeneratorT::MOC, error);
- return false;
- }
- }
- if (isOlder) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " because it's older than its source file ";
- reason += Quoted(SourceFile);
- wrk.LogInfo(GeneratorT::MOC, reason);
- }
- return true;
- }
- }
-
- // Test if a dependency file is newer
- {
- // Read dependencies on demand
- if (!DependsValid) {
- std::string content;
- {
- std::string error;
- if (!wrk.FileSys().FileRead(content, SourceFile, &error)) {
- std::string emsg = "Could not read file\n ";
- emsg += Quoted(SourceFile);
- emsg += "\nrequired by moc include ";
- emsg += Quoted(IncludeString);
- emsg += " in\n ";
- emsg += Quoted(IncluderFile);
- emsg += ".\n";
- emsg += error;
- wrk.LogError(GeneratorT::MOC, emsg);
- return false;
- }
- }
- FindDependencies(wrk, content);
- }
- // Check dependency timestamps
- std::string error;
- std::string sourceDir = wrk.FileSys().SubDirPrefix(SourceFile);
- for (std::string const& depFileRel : Depends) {
- std::string depFileAbs =
- wrk.Moc().FindIncludedFile(sourceDir, depFileRel);
- if (!depFileAbs.empty()) {
- if (wrk.FileSys().FileIsOlderThan(BuildFile, depFileAbs, &error)) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from ";
- reason += Quoted(SourceFile);
- reason += " because it is older than it's dependency file ";
- reason += Quoted(depFileAbs);
- wrk.LogInfo(GeneratorT::MOC, reason);
- }
- return true;
- }
- if (!error.empty()) {
- wrk.LogError(GeneratorT::MOC, error);
- return false;
- }
- } else {
- std::string message = "Could not find dependency file ";
- message += Quoted(depFileRel);
- wrk.LogFileWarning(GeneratorT::MOC, SourceFile, message);
- }
- }
- }
-
- return false;
-}
-
-void cmQtAutoGeneratorMocUic::JobMocT::GenerateMoc(WorkerT& wrk)
-{
- // Make sure the parent directory exists
- if (wrk.FileSys().MakeParentDirectory(GeneratorT::MOC, BuildFile)) {
- // Compose moc command
- std::vector<std::string> cmd;
- cmd.push_back(wrk.Moc().Executable);
- // Add options
- cmd.insert(cmd.end(), wrk.Moc().AllOptions.begin(),
- wrk.Moc().AllOptions.end());
- // Add predefs include
- if (!wrk.Moc().PredefsFileAbs.empty()) {
- cmd.emplace_back("--include");
- cmd.push_back(wrk.Moc().PredefsFileAbs);
- }
- cmd.emplace_back("-o");
- cmd.push_back(BuildFile);
- cmd.push_back(SourceFile);
-
- // Execute moc command
- ProcessResultT result;
- if (wrk.RunProcess(GeneratorT::MOC, result, cmd)) {
- // Moc command success
- // Print moc output
- if (!result.StdOut.empty()) {
- wrk.LogInfo(GeneratorT::MOC, result.StdOut);
- }
- // Notify the generator that a not included file changed (on demand)
- if (IncludeString.empty()) {
- wrk.Gen().ParallelMocAutoUpdated();
- }
- } else {
- // Moc command failed
- {
- std::string emsg = "The moc process failed to compile\n ";
- emsg += Quoted(SourceFile);
- emsg += "\ninto\n ";
- emsg += Quoted(BuildFile);
- emsg += ".\n";
- emsg += result.ErrorMessage;
- wrk.LogCommandError(GeneratorT::MOC, emsg, cmd, result.StdOut);
- }
- wrk.FileSys().FileRemove(BuildFile);
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::JobUicT::Process(WorkerT& wrk)
-{
- // Compute build file name
- BuildFile = wrk.Base().AutogenIncludeDir;
- BuildFile += '/';
- BuildFile += IncludeString;
-
- if (UpdateRequired(wrk)) {
- GenerateUic(wrk);
- }
-}
-
-bool cmQtAutoGeneratorMocUic::JobUicT::UpdateRequired(WorkerT& wrk)
-{
- bool const verbose = wrk.Gen().Log().Verbose();
-
- // Test if the build file exists
- if (!wrk.FileSys().FileExists(BuildFile)) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from its source file ";
- reason += Quoted(SourceFile);
- reason += " because it doesn't exist";
- wrk.LogInfo(GeneratorT::UIC, reason);
- }
- return true;
- }
-
- // Test if the uic settings changed
- if (wrk.Uic().SettingsChanged) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " from ";
- reason += Quoted(SourceFile);
- reason += " because the UIC settings changed";
- wrk.LogInfo(GeneratorT::UIC, reason);
- }
- return true;
- }
-
- // Test if the source file is newer
- {
- bool isOlder = false;
- {
- std::string error;
- isOlder = wrk.FileSys().FileIsOlderThan(BuildFile, SourceFile, &error);
- if (!isOlder && !error.empty()) {
- wrk.LogError(GeneratorT::UIC, error);
- return false;
- }
- }
- if (isOlder) {
- if (verbose) {
- std::string reason = "Generating ";
- reason += Quoted(BuildFile);
- reason += " because it's older than its source file ";
- reason += Quoted(SourceFile);
- wrk.LogInfo(GeneratorT::UIC, reason);
- }
- return true;
- }
- }
-
- return false;
-}
-
-void cmQtAutoGeneratorMocUic::JobUicT::GenerateUic(WorkerT& wrk)
-{
- // Make sure the parent directory exists
- if (wrk.FileSys().MakeParentDirectory(GeneratorT::UIC, BuildFile)) {
- // Compose uic command
- std::vector<std::string> cmd;
- cmd.push_back(wrk.Uic().Executable);
- {
- std::vector<std::string> allOpts = wrk.Uic().TargetOptions;
- auto optionIt = wrk.Uic().Options.find(SourceFile);
- if (optionIt != wrk.Uic().Options.end()) {
- UicMergeOptions(allOpts, optionIt->second,
- (wrk.Base().QtVersionMajor == 5));
- }
- cmd.insert(cmd.end(), allOpts.begin(), allOpts.end());
- }
- cmd.emplace_back("-o");
- cmd.push_back(BuildFile);
- cmd.push_back(SourceFile);
-
- ProcessResultT result;
- if (wrk.RunProcess(GeneratorT::UIC, result, cmd)) {
- // Uic command success
- // Print uic output
- if (!result.StdOut.empty()) {
- wrk.LogInfo(GeneratorT::UIC, result.StdOut);
- }
- } else {
- // Uic command failed
- {
- std::string emsg = "The uic process failed to compile\n ";
- emsg += Quoted(SourceFile);
- emsg += "\ninto\n ";
- emsg += Quoted(BuildFile);
- emsg += "\nincluded by\n ";
- emsg += Quoted(IncluderFile);
- emsg += ".\n";
- emsg += result.ErrorMessage;
- wrk.LogCommandError(GeneratorT::UIC, emsg, cmd, result.StdOut);
- }
- wrk.FileSys().FileRemove(BuildFile);
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::JobDeleterT::operator()(JobT* job)
-{
- delete job;
-}
-
-cmQtAutoGeneratorMocUic::WorkerT::WorkerT(cmQtAutoGeneratorMocUic* gen,
- uv_loop_t* uvLoop)
- : Gen_(gen)
-{
- // Initialize uv asynchronous callback for process starting
- ProcessRequest_.init(*uvLoop, &WorkerT::UVProcessStart, this);
- // Start thread
- Thread_ = std::thread(&WorkerT::Loop, this);
-}
-
-cmQtAutoGeneratorMocUic::WorkerT::~WorkerT()
-{
- // Join thread
- if (Thread_.joinable()) {
- Thread_.join();
- }
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::LogInfo(
- GeneratorT genType, std::string const& message) const
-{
- return Log().Info(genType, message);
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::LogWarning(
- GeneratorT genType, std::string const& message) const
-{
- return Log().Warning(genType, message);
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::LogFileWarning(
- GeneratorT genType, std::string const& filename,
- std::string const& message) const
-{
- return Log().WarningFile(genType, filename, message);
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::LogError(
- GeneratorT genType, std::string const& message) const
-{
- Gen().ParallelRegisterJobError();
- Log().Error(genType, message);
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::LogFileError(
- GeneratorT genType, std::string const& filename,
- std::string const& message) const
-{
- Gen().ParallelRegisterJobError();
- Log().ErrorFile(genType, filename, message);
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::LogCommandError(
- GeneratorT genType, std::string const& message,
- std::vector<std::string> const& command, std::string const& output) const
-{
- Gen().ParallelRegisterJobError();
- Log().ErrorCommand(genType, message, command, output);
-}
-
-bool cmQtAutoGeneratorMocUic::WorkerT::RunProcess(
- GeneratorT genType, ProcessResultT& result,
- std::vector<std::string> const& command)
-{
- if (command.empty()) {
- return false;
- }
-
- // Create process instance
- {
- std::lock_guard<std::mutex> lock(ProcessMutex_);
- Process_ = cm::make_unique<ReadOnlyProcessT>();
- Process_->setup(&result, true, command, Gen().Base().AutogenBuildDir);
- }
-
- // Send asynchronous process start request to libuv loop
- ProcessRequest_.send();
-
- // Log command
- if (this->Log().Verbose()) {
- std::string msg = "Running command:\n";
- msg += QuotedCommand(command);
- msg += '\n';
- this->LogInfo(genType, msg);
- }
-
- // Wait until the process has been finished and destroyed
- {
- std::unique_lock<std::mutex> ulock(ProcessMutex_);
- while (Process_) {
- ProcessCondition_.wait(ulock);
- }
- }
- return !result.error();
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::Loop()
-{
- while (true) {
- Gen().WorkerSwapJob(JobHandle_);
- if (JobHandle_) {
- JobHandle_->Process(*this);
- } else {
- break;
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::UVProcessStart(uv_async_t* handle)
-{
- auto& wrk = *reinterpret_cast<WorkerT*>(handle->data);
- {
- std::lock_guard<std::mutex> lock(wrk.ProcessMutex_);
- if (wrk.Process_ && !wrk.Process_->IsStarted()) {
- wrk.Process_->start(handle->loop, [&wrk] { wrk.UVProcessFinished(); });
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::WorkerT::UVProcessFinished()
-{
- {
- std::lock_guard<std::mutex> lock(ProcessMutex_);
- if (Process_ && Process_->IsFinished()) {
- Process_.reset();
- }
- }
- // Notify idling thread
- ProcessCondition_.notify_one();
-}
-
-cmQtAutoGeneratorMocUic::cmQtAutoGeneratorMocUic()
- : Base_(&FileSys())
- , Moc_(&FileSys())
-{
- // Precompile regular expressions
- Moc_.RegExpInclude.compile(
- "(^|\n)[ \t]*#[ \t]*include[ \t]+"
- "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
- Uic_.RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+"
- "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
-
- // Initialize libuv asynchronous iteration request
- UVRequest().init(*UVLoop(), &cmQtAutoGeneratorMocUic::UVPollStage, this);
-}
-
-cmQtAutoGeneratorMocUic::~cmQtAutoGeneratorMocUic() = default;
-
-bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile)
-{
- // -- Meta
- Base_.HeaderExtensions = makefile->GetCMakeInstance()->GetHeaderExtensions();
-
- // Utility lambdas
- auto InfoGet = [makefile](const char* key) {
- return makefile->GetSafeDefinition(key);
- };
- auto InfoGetBool = [makefile](const char* key) {
- return makefile->IsOn(key);
- };
- auto InfoGetList = [makefile](const char* key) -> std::vector<std::string> {
- std::vector<std::string> list;
- cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list);
- return list;
- };
- auto InfoGetLists =
- [makefile](const char* key) -> std::vector<std::vector<std::string>> {
- std::vector<std::vector<std::string>> lists;
- {
- std::string const value = makefile->GetSafeDefinition(key);
- std::string::size_type pos = 0;
- while (pos < value.size()) {
- std::string::size_type next = value.find(ListSep, pos);
- std::string::size_type length =
- (next != std::string::npos) ? next - pos : value.size() - pos;
- // Remove enclosing braces
- if (length >= 2) {
- std::string::const_iterator itBeg = value.begin() + (pos + 1);
- std::string::const_iterator itEnd = itBeg + (length - 2);
- {
- std::string subValue(itBeg, itEnd);
- std::vector<std::string> list;
- cmSystemTools::ExpandListArgument(subValue, list);
- lists.push_back(std::move(list));
- }
- }
- pos += length;
- pos += ListSep.size();
- }
- }
- return lists;
- };
- auto InfoGetConfig = [makefile, this](const char* key) -> std::string {
- const char* valueConf = nullptr;
- {
- std::string keyConf = key;
- keyConf += '_';
- keyConf += InfoConfig();
- valueConf = makefile->GetDefinition(keyConf);
- }
- if (valueConf == nullptr) {
- return makefile->GetSafeDefinition(key);
- }
- return std::string(valueConf);
- };
- auto InfoGetConfigList =
- [&InfoGetConfig](const char* key) -> std::vector<std::string> {
- std::vector<std::string> list;
- cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
- return list;
- };
-
- // -- Read info file
- if (!makefile->ReadListFile(InfoFile())) {
- Log().ErrorFile(GeneratorT::GEN, InfoFile(), "File processing failed");
- return false;
- }
-
- // -- Meta
- Log().RaiseVerbosity(InfoGet("AM_VERBOSITY"));
- Base_.MultiConfig = InfoGetBool("AM_MULTI_CONFIG");
- {
- unsigned long num = Base_.NumThreads;
- if (cmSystemTools::StringToULong(InfoGet("AM_PARALLEL").c_str(), &num)) {
- num = std::max<unsigned long>(num, 1);
- num = std::min<unsigned long>(num, ParallelMax);
- Base_.NumThreads = static_cast<unsigned int>(num);
- }
- }
-
- // - Files and directories
- Base_.ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR");
- Base_.ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR");
- Base_.CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR");
- Base_.CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR");
- Base_.IncludeProjectDirsBefore =
- InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
- Base_.AutogenBuildDir = InfoGet("AM_BUILD_DIR");
- if (Base_.AutogenBuildDir.empty()) {
- Log().ErrorFile(GeneratorT::GEN, InfoFile(),
- "Autogen build directory missing");
- return false;
- }
- // include directory
- Base_.AutogenIncludeDir = InfoGetConfig("AM_INCLUDE_DIR");
- if (Base_.AutogenIncludeDir.empty()) {
- Log().ErrorFile(GeneratorT::GEN, InfoFile(),
- "Autogen include directory missing");
- return false;
- }
-
- // - Files
- SettingsFile_ = InfoGetConfig("AM_SETTINGS_FILE");
- if (SettingsFile_.empty()) {
- Log().ErrorFile(GeneratorT::GEN, InfoFile(), "Settings file name missing");
- return false;
- }
-
- // - Qt environment
- {
- unsigned long qtv = Base_.QtVersionMajor;
- if (cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR").c_str(),
- &qtv)) {
- Base_.QtVersionMajor = static_cast<unsigned int>(qtv);
- }
- }
-
- // - Moc
- Moc_.Executable = InfoGet("AM_QT_MOC_EXECUTABLE");
- Moc_.Enabled = !Moc().Executable.empty();
- if (Moc().Enabled) {
- {
- auto lst = InfoGetList("AM_MOC_SKIP");
- Moc_.SkipList.insert(lst.begin(), lst.end());
- }
- Moc_.Definitions = InfoGetConfigList("AM_MOC_DEFINITIONS");
- Moc_.IncludePaths = InfoGetConfigList("AM_MOC_INCLUDES");
- Moc_.Options = InfoGetList("AM_MOC_OPTIONS");
- Moc_.RelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE");
- for (std::string const& item : InfoGetList("AM_MOC_MACRO_NAMES")) {
- Moc_.MacroFilters.emplace_back(
- item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
- }
- {
- auto pushFilter = [this](std::string const& key, std::string const& exp,
- std::string& error) {
- if (!key.empty()) {
- if (!exp.empty()) {
- Moc_.DependFilters.emplace_back();
- KeyExpT& filter(Moc_.DependFilters.back());
- if (filter.Exp.compile(exp)) {
- filter.Key = key;
- } else {
- error = "Regular expression compiling failed";
- }
- } else {
- error = "Regular expression is empty";
- }
- } else {
- error = "Key is empty";
- }
- if (!error.empty()) {
- error = ("AUTOMOC_DEPEND_FILTERS: " + error);
- error += "\n";
- error += " Key: ";
- error += Quoted(key);
- error += "\n";
- error += " Exp: ";
- error += Quoted(exp);
- error += "\n";
- }
- };
-
- std::string error;
- // Insert default filter for Q_PLUGIN_METADATA
- if (Base().QtVersionMajor != 4) {
- pushFilter("Q_PLUGIN_METADATA",
- "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
- "[^\\)]*FILE[ \t]*\"([^\"]+)\"",
- error);
- }
- // Insert user defined dependency filters
- {
- std::vector<std::string> flts = InfoGetList("AM_MOC_DEPEND_FILTERS");
- if ((flts.size() % 2) == 0) {
- for (std::vector<std::string>::iterator itC = flts.begin(),
- itE = flts.end();
- itC != itE; itC += 2) {
- pushFilter(*itC, *(itC + 1), error);
- if (!error.empty()) {
- break;
- }
- }
- } else {
- Log().ErrorFile(
- GeneratorT::MOC, InfoFile(),
- "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2");
- return false;
- }
- }
- if (!error.empty()) {
- Log().ErrorFile(GeneratorT::MOC, InfoFile(), error);
- return false;
- }
- }
- Moc_.PredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD");
- // Install moc predefs job
- if (!Moc().PredefsCmd.empty()) {
- JobQueues_.MocPredefs.emplace_back(new JobMocPredefsT());
- }
- }
-
- // - Uic
- Uic_.Executable = InfoGet("AM_QT_UIC_EXECUTABLE");
- Uic_.Enabled = !Uic().Executable.empty();
- if (Uic().Enabled) {
- {
- auto lst = InfoGetList("AM_UIC_SKIP");
- Uic_.SkipList.insert(lst.begin(), lst.end());
- }
- Uic_.SearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS");
- Uic_.TargetOptions = InfoGetConfigList("AM_UIC_TARGET_OPTIONS");
- {
- auto sources = InfoGetList("AM_UIC_OPTIONS_FILES");
- auto options = InfoGetLists("AM_UIC_OPTIONS_OPTIONS");
- // Compare list sizes
- if (sources.size() != options.size()) {
- std::ostringstream ost;
- ost << "files/options lists sizes mismatch (" << sources.size() << "/"
- << options.size() << ")";
- Log().ErrorFile(GeneratorT::UIC, InfoFile(), ost.str());
- return false;
- }
- auto fitEnd = sources.cend();
- auto fit = sources.begin();
- auto oit = options.begin();
- while (fit != fitEnd) {
- Uic_.Options[*fit] = std::move(*oit);
- ++fit;
- ++oit;
- }
- }
- }
-
- // Initialize source file jobs
- {
- std::hash<std::string> stringHash;
- std::set<std::size_t> uniqueHeaders;
-
- // Add header jobs
- for (std::string& hdr : InfoGetList("AM_HEADERS")) {
- const bool moc = !Moc().skipped(hdr);
- const bool uic = !Uic().skipped(hdr);
- if ((moc || uic) && uniqueHeaders.emplace(stringHash(hdr)).second) {
- JobQueues_.Headers.emplace_back(
- new JobParseT(std::move(hdr), moc, uic, true));
- }
- }
- // Add source jobs
- {
- std::vector<std::string> sources = InfoGetList("AM_SOURCES");
- // Add header(s) for the source file
- for (std::string& src : sources) {
- const bool srcMoc = !Moc().skipped(src);
- const bool srcUic = !Uic().skipped(src);
- if (!srcMoc && !srcUic) {
- continue;
- }
- // Search for the default header file and a private header
- {
- std::array<std::string, 2> bases;
- bases[0] = FileSys().SubDirPrefix(src);
- bases[0] += FileSys().GetFilenameWithoutLastExtension(src);
- bases[1] = bases[0];
- bases[1] += "_p";
- for (std::string const& headerBase : bases) {
- std::string header;
- if (Base().FindHeader(header, headerBase)) {
- const bool moc = srcMoc && !Moc().skipped(header);
- const bool uic = srcUic && !Uic().skipped(header);
- if ((moc || uic) &&
- uniqueHeaders.emplace(stringHash(header)).second) {
- JobQueues_.Headers.emplace_back(
- new JobParseT(std::move(header), moc, uic, true));
- }
- }
- }
- }
- // Add source job
- JobQueues_.Sources.emplace_back(
- new JobParseT(std::move(src), srcMoc, srcUic));
- }
- }
- }
-
- // Init derived information
- // ------------------------
-
- // Init file path checksum generator
- FileSys().setupFilePathChecksum(
- Base().CurrentSourceDir, Base().CurrentBinaryDir, Base().ProjectSourceDir,
- Base().ProjectBinaryDir);
-
- // Moc variables
- if (Moc().Enabled) {
- // Mocs compilation file
- Moc_.CompFileAbs = Base().AbsoluteBuildPath("mocs_compilation.cpp");
-
- // Moc predefs file
- if (!Moc_.PredefsCmd.empty()) {
- Moc_.PredefsFileRel = "moc_predefs";
- if (Base_.MultiConfig) {
- Moc_.PredefsFileRel += '_';
- Moc_.PredefsFileRel += InfoConfig();
- }
- Moc_.PredefsFileRel += ".h";
- Moc_.PredefsFileAbs = Base_.AbsoluteBuildPath(Moc().PredefsFileRel);
- }
-
- // Sort include directories on demand
- if (Base().IncludeProjectDirsBefore) {
- // Move strings to temporary list
- std::list<std::string> includes;
- includes.insert(includes.end(), Moc().IncludePaths.begin(),
- Moc().IncludePaths.end());
- Moc_.IncludePaths.clear();
- Moc_.IncludePaths.reserve(includes.size());
- // Append project directories only
- {
- std::array<std::string const*, 2> const movePaths = {
- { &Base().ProjectBinaryDir, &Base().ProjectSourceDir }
- };
- for (std::string const* ppath : movePaths) {
- std::list<std::string>::iterator it = includes.begin();
- while (it != includes.end()) {
- std::string const& path = *it;
- if (cmSystemTools::StringStartsWith(path, ppath->c_str())) {
- Moc_.IncludePaths.push_back(path);
- it = includes.erase(it);
- } else {
- ++it;
- }
- }
- }
- }
- // Append remaining directories
- Moc_.IncludePaths.insert(Moc_.IncludePaths.end(), includes.begin(),
- includes.end());
- }
- // Compose moc includes list
- {
- std::set<std::string> frameworkPaths;
- for (std::string const& path : Moc().IncludePaths) {
- Moc_.Includes.push_back("-I" + path);
- // Extract framework path
- if (cmHasLiteralSuffix(path, ".framework/Headers")) {
- // Go up twice to get to the framework root
- std::vector<std::string> pathComponents;
- FileSys().SplitPath(path, pathComponents);
- std::string frameworkPath = FileSys().JoinPath(
- pathComponents.begin(), pathComponents.end() - 2);
- frameworkPaths.insert(frameworkPath);
- }
- }
- // Append framework includes
- for (std::string const& path : frameworkPaths) {
- Moc_.Includes.emplace_back("-F");
- Moc_.Includes.push_back(path);
- }
- }
- // Setup single list with all options
- {
- // Add includes
- Moc_.AllOptions.insert(Moc_.AllOptions.end(), Moc().Includes.begin(),
- Moc().Includes.end());
- // Add definitions
- for (std::string const& def : Moc().Definitions) {
- Moc_.AllOptions.push_back("-D" + def);
- }
- // Add options
- Moc_.AllOptions.insert(Moc_.AllOptions.end(), Moc().Options.begin(),
- Moc().Options.end());
- }
- }
-
- return true;
-}
-
-bool cmQtAutoGeneratorMocUic::Process()
-{
- // Run libuv event loop
- UVRequest().send();
- if (uv_run(UVLoop(), UV_RUN_DEFAULT) == 0) {
- if (JobError_) {
- return false;
- }
- } else {
- return false;
- }
- return true;
-}
-
-void cmQtAutoGeneratorMocUic::UVPollStage(uv_async_t* handle)
-{
- reinterpret_cast<cmQtAutoGeneratorMocUic*>(handle->data)->PollStage();
-}
-
-void cmQtAutoGeneratorMocUic::PollStage()
-{
- switch (Stage_) {
- case StageT::SETTINGS_READ:
- SettingsFileRead();
- SetStage(StageT::CREATE_DIRECTORIES);
- break;
- case StageT::CREATE_DIRECTORIES:
- CreateDirectories();
- SetStage(StageT::PARSE_SOURCES);
- break;
- case StageT::PARSE_SOURCES:
- if (ThreadsStartJobs(JobQueues_.Sources)) {
- SetStage(StageT::PARSE_HEADERS);
- }
- break;
- case StageT::PARSE_HEADERS:
- if (ThreadsStartJobs(JobQueues_.Headers)) {
- SetStage(StageT::MOC_PREDEFS);
- }
- break;
- case StageT::MOC_PREDEFS:
- if (ThreadsStartJobs(JobQueues_.MocPredefs)) {
- SetStage(StageT::MOC_PROCESS);
- }
- break;
- case StageT::MOC_PROCESS:
- if (ThreadsStartJobs(JobQueues_.Moc)) {
- SetStage(StageT::MOCS_COMPILATION);
- }
- break;
- case StageT::MOCS_COMPILATION:
- if (ThreadsJobsDone()) {
- MocGenerateCompilation();
- SetStage(StageT::UIC_PROCESS);
- }
- break;
- case StageT::UIC_PROCESS:
- if (ThreadsStartJobs(JobQueues_.Uic)) {
- SetStage(StageT::SETTINGS_WRITE);
- }
- break;
- case StageT::SETTINGS_WRITE:
- SettingsFileWrite();
- SetStage(StageT::FINISH);
- break;
- case StageT::FINISH:
- if (ThreadsJobsDone()) {
- // Clear all libuv handles
- ThreadsStop();
- UVRequest().reset();
- // Set highest END stage manually
- Stage_ = StageT::END;
- }
- break;
- case StageT::END:
- break;
- }
-}
-
-void cmQtAutoGeneratorMocUic::SetStage(StageT stage)
-{
- if (JobError_) {
- stage = StageT::FINISH;
- }
- // Only allow to increase the stage
- if (Stage_ < stage) {
- Stage_ = stage;
- UVRequest().send();
- }
-}
-
-void cmQtAutoGeneratorMocUic::SettingsFileRead()
-{
- // Compose current settings strings
- {
- cmCryptoHash crypt(cmCryptoHash::AlgoSHA256);
- std::string const sep(" ~~~ ");
- if (Moc_.Enabled) {
- std::string str;
- str += Moc().Executable;
- str += sep;
- str += cmJoin(Moc().AllOptions, ";");
- str += sep;
- str += Base().IncludeProjectDirsBefore ? "TRUE" : "FALSE";
- str += sep;
- str += cmJoin(Moc().PredefsCmd, ";");
- str += sep;
- SettingsStringMoc_ = crypt.HashString(str);
- }
- if (Uic().Enabled) {
- std::string str;
- str += Uic().Executable;
- str += sep;
- str += cmJoin(Uic().TargetOptions, ";");
- for (const auto& item : Uic().Options) {
- str += sep;
- str += item.first;
- str += sep;
- str += cmJoin(item.second, ";");
- }
- str += sep;
- SettingsStringUic_ = crypt.HashString(str);
- }
- }
-
- // Read old settings and compare
- {
- std::string content;
- if (FileSys().FileRead(content, SettingsFile_)) {
- if (Moc().Enabled) {
- if (SettingsStringMoc_ != SettingsFind(content, "moc")) {
- Moc_.SettingsChanged = true;
- }
- }
- if (Uic().Enabled) {
- if (SettingsStringUic_ != SettingsFind(content, "uic")) {
- Uic_.SettingsChanged = true;
- }
- }
- // In case any setting changed remove the old settings file.
- // This triggers a full rebuild on the next run if the current
- // build is aborted before writing the current settings in the end.
- if (Moc().SettingsChanged || Uic().SettingsChanged) {
- FileSys().FileRemove(SettingsFile_);
- }
- } else {
- // Settings file read failed
- if (Moc().Enabled) {
- Moc_.SettingsChanged = true;
- }
- if (Uic().Enabled) {
- Uic_.SettingsChanged = true;
- }
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::SettingsFileWrite()
-{
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- // Only write if any setting changed
- if (!JobError_ && (Moc().SettingsChanged || Uic().SettingsChanged)) {
- if (Log().Verbose()) {
- Log().Info(GeneratorT::GEN,
- "Writing settings file " + Quoted(SettingsFile_));
- }
- // Compose settings file content
- std::string content;
- {
- auto SettingAppend = [&content](const char* key,
- std::string const& value) {
- if (!value.empty()) {
- content += key;
- content += ':';
- content += value;
- content += '\n';
- }
- };
- SettingAppend("moc", SettingsStringMoc_);
- SettingAppend("uic", SettingsStringUic_);
- }
- // Write settings file
- if (!FileSys().FileWrite(GeneratorT::GEN, SettingsFile_, content)) {
- Log().ErrorFile(GeneratorT::GEN, SettingsFile_,
- "Settings file writing failed");
- // Remove old settings file to trigger a full rebuild on the next run
- FileSys().FileRemove(SettingsFile_);
- RegisterJobError();
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::CreateDirectories()
-{
- // Create AUTOGEN include directory
- if (!FileSys().MakeDirectory(GeneratorT::GEN, Base().AutogenIncludeDir)) {
- RegisterJobError();
- }
-}
-
-bool cmQtAutoGeneratorMocUic::ThreadsStartJobs(JobQueueT& queue)
-{
- bool done = false;
- std::size_t queueSize = queue.size();
-
- // Change the active queue
- {
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- // Check if there are still unfinished jobs from the previous queue
- if (JobsRemain_ == 0) {
- if (!JobThreadsAbort_) {
- JobQueue_.swap(queue);
- JobsRemain_ = queueSize;
- } else {
- // Abort requested
- queue.clear();
- queueSize = 0;
- }
- done = true;
- }
- }
-
- if (done && (queueSize != 0)) {
- // Start new threads on demand
- if (Workers_.empty()) {
- Workers_.resize(Base().NumThreads);
- for (auto& item : Workers_) {
- item = cm::make_unique<WorkerT>(this, UVLoop());
- }
- } else {
- // Notify threads
- if (queueSize == 1) {
- JobsConditionRead_.notify_one();
- } else {
- JobsConditionRead_.notify_all();
- }
- }
- }
-
- return done;
-}
-
-void cmQtAutoGeneratorMocUic::ThreadsStop()
-{
- if (!Workers_.empty()) {
- // Clear all jobs
- {
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- JobThreadsAbort_ = true;
- JobsRemain_ -= JobQueue_.size();
- JobQueue_.clear();
-
- JobQueues_.Sources.clear();
- JobQueues_.Headers.clear();
- JobQueues_.MocPredefs.clear();
- JobQueues_.Moc.clear();
- JobQueues_.Uic.clear();
- }
- // Wake threads
- JobsConditionRead_.notify_all();
- // Join and clear threads
- Workers_.clear();
- }
-}
-
-bool cmQtAutoGeneratorMocUic::ThreadsJobsDone()
-{
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- return (JobsRemain_ == 0);
-}
-
-void cmQtAutoGeneratorMocUic::WorkerSwapJob(JobHandleT& jobHandle)
-{
- bool const jobProcessed(jobHandle);
- if (jobProcessed) {
- jobHandle.reset(nullptr);
- }
- {
- std::unique_lock<std::mutex> jobsLock(JobsMutex_);
- // Reduce the remaining job count and notify the libuv loop
- // when all jobs are done
- if (jobProcessed) {
- --JobsRemain_;
- if (JobsRemain_ == 0) {
- UVRequest().send();
- }
- }
- // Wait for new jobs
- while (!JobThreadsAbort_ && JobQueue_.empty()) {
- JobsConditionRead_.wait(jobsLock);
- }
- // Try to pick up a new job handle
- if (!JobThreadsAbort_ && !JobQueue_.empty()) {
- jobHandle = std::move(JobQueue_.front());
- JobQueue_.pop_front();
- }
- }
-}
-
-void cmQtAutoGeneratorMocUic::ParallelRegisterJobError()
-{
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- RegisterJobError();
-}
-
-// Private method that requires cmQtAutoGeneratorMocUic::JobsMutex_ to be
-// locked
-void cmQtAutoGeneratorMocUic::RegisterJobError()
-{
- JobError_ = true;
- if (!JobThreadsAbort_) {
- JobThreadsAbort_ = true;
- // Clear remaining jobs
- if (JobsRemain_ != 0) {
- JobsRemain_ -= JobQueue_.size();
- JobQueue_.clear();
- }
- }
-}
-
-bool cmQtAutoGeneratorMocUic::ParallelJobPushMoc(JobHandleT& jobHandle)
-{
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- if (!JobThreadsAbort_) {
- bool pushJobHandle = true;
- // Do additional tests if this is an included moc job
- const JobMocT& mocJob(static_cast<JobMocT&>(*jobHandle));
- if (!mocJob.IncludeString.empty()) {
- // Register included moc file and look for collisions
- MocIncludedFiles_.emplace(mocJob.SourceFile);
- if (!MocIncludedStrings_.emplace(mocJob.IncludeString).second) {
- // Another source file includes the same moc file!
- for (const JobHandleT& otherHandle : JobQueues_.Moc) {
- const JobMocT& otherJob(static_cast<JobMocT&>(*otherHandle));
- if (otherJob.IncludeString == mocJob.IncludeString) {
- // Check if the same moc file would be generated from different
- // source files which is an error.
- if (otherJob.SourceFile != mocJob.SourceFile) {
- // Include string collision
- std::string error = "The two source files\n ";
- error += Quoted(mocJob.IncluderFile);
- error += " and\n ";
- error += Quoted(otherJob.IncluderFile);
- error += "\ncontain the same moc include string ";
- error += Quoted(mocJob.IncludeString);
- error += "\nbut the moc file would be generated from different "
- "source files\n ";
- error += Quoted(mocJob.SourceFile);
- error += " and\n ";
- error += Quoted(otherJob.SourceFile);
- error += ".\nConsider to\n"
- "- not include the \"moc_<NAME>.cpp\" file\n"
- "- add a directory prefix to a \"<NAME>.moc\" include "
- "(e.g \"sub/<NAME>.moc\")\n"
- "- rename the source file(s)\n";
- Log().Error(GeneratorT::MOC, error);
- RegisterJobError();
- }
- // Do not push this job in since the included moc file already
- // gets generated by an other job.
- pushJobHandle = false;
- break;
- }
- }
- }
- }
- // Push job on demand
- if (pushJobHandle) {
- JobQueues_.Moc.emplace_back(std::move(jobHandle));
- }
- }
- return !JobError_;
-}
-
-bool cmQtAutoGeneratorMocUic::ParallelJobPushUic(JobHandleT& jobHandle)
-{
- std::lock_guard<std::mutex> jobsLock(JobsMutex_);
- if (!JobThreadsAbort_) {
- bool pushJobHandle = true;
- // Look for include collisions.
- const JobUicT& uicJob(static_cast<JobUicT&>(*jobHandle));
- for (const JobHandleT& otherHandle : JobQueues_.Uic) {
- const JobUicT& otherJob(static_cast<JobUicT&>(*otherHandle));
- if (otherJob.IncludeString == uicJob.IncludeString) {
- // Check if the same uic file would be generated from different
- // source files which would be an error.
- if (otherJob.SourceFile != uicJob.SourceFile) {
- // Include string collision
- std::string error = "The two source files\n ";
- error += Quoted(uicJob.IncluderFile);
- error += " and\n ";
- error += Quoted(otherJob.IncluderFile);
- error += "\ncontain the same uic include string ";
- error += Quoted(uicJob.IncludeString);
- error += "\nbut the uic file would be generated from different "
- "source files\n ";
- error += Quoted(uicJob.SourceFile);
- error += " and\n ";
- error += Quoted(otherJob.SourceFile);
- error +=
- ".\nConsider to\n"
- "- add a directory prefix to a \"ui_<NAME>.h\" include "
- "(e.g \"sub/ui_<NAME>.h\")\n"
- "- rename the <NAME>.ui file(s) and adjust the \"ui_<NAME>.h\" "
- "include(s)\n";
- Log().Error(GeneratorT::UIC, error);
- RegisterJobError();
- }
- // Do not push this job in since the uic file already
- // gets generated by an other job.
- pushJobHandle = false;
- break;
- }
- }
- if (pushJobHandle) {
- JobQueues_.Uic.emplace_back(std::move(jobHandle));
- }
- }
- return !JobError_;
-}
-
-bool cmQtAutoGeneratorMocUic::ParallelMocIncluded(
- std::string const& sourceFile)
-{
- std::lock_guard<std::mutex> mocLock(JobsMutex_);
- return (MocIncludedFiles_.find(sourceFile) != MocIncludedFiles_.end());
-}
-
-std::string cmQtAutoGeneratorMocUic::ParallelMocAutoRegister(
- std::string const& baseName)
-{
- std::string res;
- {
- std::lock_guard<std::mutex> mocLock(JobsMutex_);
- res = baseName;
- res += ".cpp";
- if (MocAutoFiles_.find(res) == MocAutoFiles_.end()) {
- MocAutoFiles_.emplace(res);
- } else {
- // Append number suffix to the file name
- for (unsigned int ii = 2; ii != 1024; ++ii) {
- res = baseName;
- res += '_';
- res += std::to_string(ii);
- res += ".cpp";
- if (MocAutoFiles_.find(res) == MocAutoFiles_.end()) {
- MocAutoFiles_.emplace(res);
- break;
- }
- }
- }
- }
- return res;
-}
-
-void cmQtAutoGeneratorMocUic::ParallelMocAutoUpdated()
-{
- std::lock_guard<std::mutex> mocLock(JobsMutex_);
- MocAutoFileUpdated_ = true;
-}
-
-void cmQtAutoGeneratorMocUic::MocGenerateCompilation()
-{
- std::lock_guard<std::mutex> mocLock(JobsMutex_);
- if (!JobError_ && Moc().Enabled) {
- // Write mocs compilation build file
- {
- // Compose mocs compilation file content
- std::string content =
- "// This file is autogenerated. Changes will be overwritten.\n";
- if (MocAutoFiles_.empty()) {
- // Placeholder content
- content += "// No files found that require moc or the moc files are "
- "included\n";
- content += "enum some_compilers { need_more_than_nothing };\n";
- } else {
- // Valid content
- char const sbeg = Base().MultiConfig ? '<' : '"';
- char const send = Base().MultiConfig ? '>' : '"';
- for (std::string const& mocfile : MocAutoFiles_) {
- content += "#include ";
- content += sbeg;
- content += mocfile;
- content += send;
- content += '\n';
- }
- }
-
- std::string const& compAbs = Moc().CompFileAbs;
- if (FileSys().FileDiffers(compAbs, content)) {
- // Actually write mocs compilation file
- if (Log().Verbose()) {
- Log().Info(GeneratorT::MOC, "Generating MOC compilation " + compAbs);
- }
- if (!FileSys().FileWrite(GeneratorT::MOC, compAbs, content)) {
- Log().ErrorFile(GeneratorT::MOC, compAbs,
- "mocs compilation file writing failed");
- RegisterJobError();
- return;
- }
- } else if (MocAutoFileUpdated_) {
- // Only touch mocs compilation file
- if (Log().Verbose()) {
- Log().Info(GeneratorT::MOC, "Touching mocs compilation " + compAbs);
- }
- FileSys().Touch(compAbs);
- }
- }
- // Write mocs compilation wrapper file
- if (Base().MultiConfig) {
- }
- }
-}
diff --git a/Source/cmQtAutoGeneratorMocUic.h b/Source/cmQtAutoGeneratorMocUic.h
deleted file mode 100644
index c22df29ab..000000000
--- a/Source/cmQtAutoGeneratorMocUic.h
+++ /dev/null
@@ -1,450 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#ifndef cmQtAutoGeneratorMocUic_h
-#define cmQtAutoGeneratorMocUic_h
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include "cmQtAutoGen.h"
-#include "cmQtAutoGenerator.h"
-#include "cmUVHandlePtr.h"
-#include "cm_uv.h"
-#include "cmsys/RegularExpression.hxx"
-
-#include <condition_variable>
-#include <cstddef>
-#include <deque>
-#include <map>
-#include <memory> // IWYU pragma: keep
-#include <mutex>
-#include <set>
-#include <string>
-#include <thread>
-#include <utility>
-#include <vector>
-
-class cmMakefile;
-
-// @brief AUTOMOC and AUTOUIC generator
-class cmQtAutoGeneratorMocUic : public cmQtAutoGenerator
-{
-public:
- cmQtAutoGeneratorMocUic();
- ~cmQtAutoGeneratorMocUic() override;
-
- cmQtAutoGeneratorMocUic(cmQtAutoGeneratorMocUic const&) = delete;
- cmQtAutoGeneratorMocUic& operator=(cmQtAutoGeneratorMocUic const&) = delete;
-
-public:
- // -- Types
- class WorkerT;
-
- /// @brief Search key plus regular expression pair
- ///
- struct KeyExpT
- {
- KeyExpT() = default;
-
- KeyExpT(const char* key, const char* exp)
- : Key(key)
- , Exp(exp)
- {
- }
-
- KeyExpT(std::string key, std::string const& exp)
- : Key(std::move(key))
- , Exp(exp)
- {
- }
-
- std::string Key;
- cmsys::RegularExpression Exp;
- };
-
- /// @brief Common settings
- ///
- class BaseSettingsT
- {
- public:
- // -- Volatile methods
- BaseSettingsT(FileSystem* fileSystem)
- : MultiConfig(false)
- , IncludeProjectDirsBefore(false)
- , QtVersionMajor(4)
- , NumThreads(1)
- , FileSys(fileSystem)
- {
- }
-
- BaseSettingsT(BaseSettingsT const&) = delete;
- BaseSettingsT& operator=(BaseSettingsT const&) = delete;
-
- // -- Const methods
- std::string AbsoluteBuildPath(std::string const& relativePath) const;
- bool FindHeader(std::string& header,
- std::string const& testBasePath) const;
-
- // -- Attributes
- // - Config
- bool MultiConfig;
- bool IncludeProjectDirsBefore;
- unsigned int QtVersionMajor;
- unsigned int NumThreads;
- // - Directories
- std::string ProjectSourceDir;
- std::string ProjectBinaryDir;
- std::string CurrentSourceDir;
- std::string CurrentBinaryDir;
- std::string AutogenBuildDir;
- std::string AutogenIncludeDir;
- // - Files
- std::vector<std::string> HeaderExtensions;
- // - File system
- FileSystem* FileSys;
- };
-
- /// @brief Moc settings
- ///
- class MocSettingsT
- {
- public:
- MocSettingsT(FileSystem* fileSys)
- : FileSys(fileSys)
- {
- }
-
- MocSettingsT(MocSettingsT const&) = delete;
- MocSettingsT& operator=(MocSettingsT const&) = delete;
-
- // -- Const methods
- bool skipped(std::string const& fileName) const;
- std::string FindMacro(std::string const& content) const;
- std::string MacrosString() const;
- std::string FindIncludedFile(std::string const& sourcePath,
- std::string const& includeString) const;
- void FindDependencies(std::string const& content,
- std::set<std::string>& depends) const;
-
- // -- Attributes
- bool Enabled = false;
- bool SettingsChanged = false;
- bool RelaxedMode = false;
- std::string Executable;
- std::string CompFileAbs;
- std::string PredefsFileRel;
- std::string PredefsFileAbs;
- std::set<std::string> SkipList;
- std::vector<std::string> IncludePaths;
- std::vector<std::string> Includes;
- std::vector<std::string> Definitions;
- std::vector<std::string> Options;
- std::vector<std::string> AllOptions;
- std::vector<std::string> PredefsCmd;
- std::vector<KeyExpT> DependFilters;
- std::vector<KeyExpT> MacroFilters;
- cmsys::RegularExpression RegExpInclude;
- // - File system
- FileSystem* FileSys;
- };
-
- /// @brief Uic settings
- ///
- class UicSettingsT
- {
- public:
- UicSettingsT() = default;
-
- UicSettingsT(UicSettingsT const&) = delete;
- UicSettingsT& operator=(UicSettingsT const&) = delete;
-
- // -- Const methods
- bool skipped(std::string const& fileName) const;
-
- // -- Attributes
- bool Enabled = false;
- bool SettingsChanged = false;
- std::string Executable;
- std::set<std::string> SkipList;
- std::vector<std::string> TargetOptions;
- std::map<std::string, std::vector<std::string>> Options;
- std::vector<std::string> SearchPaths;
- cmsys::RegularExpression RegExpInclude;
- };
-
- /// @brief Abstract job class for threaded processing
- ///
- class JobT
- {
- public:
- JobT() = default;
- virtual ~JobT() = default;
-
- JobT(JobT const&) = delete;
- JobT& operator=(JobT const&) = delete;
-
- // -- Abstract processing interface
- virtual void Process(WorkerT& wrk) = 0;
- };
-
- /// @brief Deleter for classes derived from Job
- ///
- struct JobDeleterT
- {
- void operator()(JobT* job);
- };
-
- // Job management types
- typedef std::unique_ptr<JobT, JobDeleterT> JobHandleT;
- typedef std::deque<JobHandleT> JobQueueT;
-
- /// @brief Parse source job
- ///
- class JobParseT : public JobT
- {
- public:
- JobParseT(std::string&& fileName, bool moc, bool uic, bool header = false)
- : FileName(std::move(fileName))
- , AutoMoc(moc)
- , AutoUic(uic)
- , Header(header)
- {
- }
-
- private:
- struct MetaT
- {
- std::string Content;
- std::string FileDir;
- std::string FileBase;
- };
-
- void Process(WorkerT& wrk) override;
- bool ParseMocSource(WorkerT& wrk, MetaT const& meta);
- bool ParseMocHeader(WorkerT& wrk, MetaT const& meta);
- std::string MocStringHeaders(WorkerT& wrk,
- std::string const& fileBase) const;
- std::string MocFindIncludedHeader(WorkerT& wrk,
- std::string const& includerDir,
- std::string const& includeBase);
- bool ParseUic(WorkerT& wrk, MetaT const& meta);
- bool ParseUicInclude(WorkerT& wrk, MetaT const& meta,
- std::string&& includeString);
- std::string UicFindIncludedFile(WorkerT& wrk, MetaT const& meta,
- std::string const& includeString);
-
- private:
- std::string FileName;
- bool AutoMoc = false;
- bool AutoUic = false;
- bool Header = false;
- };
-
- /// @brief Generate moc_predefs
- ///
- class JobMocPredefsT : public JobT
- {
- private:
- void Process(WorkerT& wrk) override;
- };
-
- /// @brief Moc a file job
- ///
- class JobMocT : public JobT
- {
- public:
- JobMocT(std::string&& sourceFile, std::string includerFile,
- std::string&& includeString)
- : SourceFile(std::move(sourceFile))
- , IncluderFile(std::move(includerFile))
- , IncludeString(std::move(includeString))
- {
- }
-
- void FindDependencies(WorkerT& wrk, std::string const& content);
-
- private:
- void Process(WorkerT& wrk) override;
- bool UpdateRequired(WorkerT& wrk);
- void GenerateMoc(WorkerT& wrk);
-
- public:
- std::string SourceFile;
- std::string IncluderFile;
- std::string IncludeString;
- std::string BuildFile;
- bool DependsValid = false;
- std::set<std::string> Depends;
- };
-
- /// @brief Uic a file job
- ///
- class JobUicT : public JobT
- {
- public:
- JobUicT(std::string&& sourceFile, std::string includerFile,
- std::string&& includeString)
- : SourceFile(std::move(sourceFile))
- , IncluderFile(std::move(includerFile))
- , IncludeString(std::move(includeString))
- {
- }
-
- private:
- void Process(WorkerT& wrk) override;
- bool UpdateRequired(WorkerT& wrk);
- void GenerateUic(WorkerT& wrk);
-
- public:
- std::string SourceFile;
- std::string IncluderFile;
- std::string IncludeString;
- std::string BuildFile;
- };
-
- /// @brief Worker Thread
- ///
- class WorkerT
- {
- public:
- WorkerT(cmQtAutoGeneratorMocUic* gen, uv_loop_t* uvLoop);
- ~WorkerT();
-
- WorkerT(WorkerT const&) = delete;
- WorkerT& operator=(WorkerT const&) = delete;
-
- // -- Const accessors
- cmQtAutoGeneratorMocUic& Gen() const { return *Gen_; }
- Logger& Log() const { return Gen_->Log(); }
- FileSystem& FileSys() const { return Gen_->FileSys(); }
- const BaseSettingsT& Base() const { return Gen_->Base(); }
- const MocSettingsT& Moc() const { return Gen_->Moc(); }
- const UicSettingsT& Uic() const { return Gen_->Uic(); }
-
- // -- Log info
- void LogInfo(GeneratorT genType, std::string const& message) const;
- // -- Log warning
- void LogWarning(GeneratorT genType, std::string const& message) const;
- void LogFileWarning(GeneratorT genType, std::string const& filename,
- std::string const& message) const;
- // -- Log error
- void LogError(GeneratorT genType, std::string const& message) const;
- void LogFileError(GeneratorT genType, std::string const& filename,
- std::string const& message) const;
- void LogCommandError(GeneratorT genType, std::string const& message,
- std::vector<std::string> const& command,
- std::string const& output) const;
-
- // -- External processes
- /// @brief Verbose logging version
- bool RunProcess(GeneratorT genType, ProcessResultT& result,
- std::vector<std::string> const& command);
-
- private:
- /// @brief Thread main loop
- void Loop();
-
- // -- Libuv callbacks
- static void UVProcessStart(uv_async_t* handle);
- void UVProcessFinished();
-
- private:
- // -- Generator
- cmQtAutoGeneratorMocUic* Gen_;
- // -- Job handle
- JobHandleT JobHandle_;
- // -- Process management
- std::mutex ProcessMutex_;
- cm::uv_async_ptr ProcessRequest_;
- std::condition_variable ProcessCondition_;
- std::unique_ptr<ReadOnlyProcessT> Process_;
- // -- System thread
- std::thread Thread_;
- };
-
- /// @brief Processing stage
- enum class StageT
- {
- SETTINGS_READ,
- CREATE_DIRECTORIES,
- PARSE_SOURCES,
- PARSE_HEADERS,
- MOC_PREDEFS,
- MOC_PROCESS,
- MOCS_COMPILATION,
- UIC_PROCESS,
- SETTINGS_WRITE,
- FINISH,
- END
- };
-
- // -- Const settings interface
- const BaseSettingsT& Base() const { return this->Base_; }
- const MocSettingsT& Moc() const { return this->Moc_; }
- const UicSettingsT& Uic() const { return this->Uic_; }
-
- // -- Worker thread interface
- void WorkerSwapJob(JobHandleT& jobHandle);
- // -- Parallel job processing interface
- void ParallelRegisterJobError();
- bool ParallelJobPushMoc(JobHandleT& jobHandle);
- bool ParallelJobPushUic(JobHandleT& jobHandle);
- bool ParallelMocIncluded(std::string const& sourceFile);
- std::string ParallelMocAutoRegister(std::string const& baseName);
- void ParallelMocAutoUpdated();
-
-private:
- // -- Abstract processing interface
- bool Init(cmMakefile* makefile) override;
- bool Process() override;
- // -- Process stage
- static void UVPollStage(uv_async_t* handle);
- void PollStage();
- void SetStage(StageT stage);
- // -- Settings file
- void SettingsFileRead();
- void SettingsFileWrite();
- // -- Thread processing
- bool ThreadsStartJobs(JobQueueT& queue);
- bool ThreadsJobsDone();
- void ThreadsStop();
- void RegisterJobError();
- // -- Generation
- void CreateDirectories();
- void MocGenerateCompilation();
-
-private:
- // -- Settings
- BaseSettingsT Base_;
- MocSettingsT Moc_;
- UicSettingsT Uic_;
- // -- Progress
- StageT Stage_ = StageT::SETTINGS_READ;
- // -- Job queues
- std::mutex JobsMutex_;
- struct
- {
- JobQueueT Sources;
- JobQueueT Headers;
- JobQueueT MocPredefs;
- JobQueueT Moc;
- JobQueueT Uic;
- } JobQueues_;
- JobQueueT JobQueue_;
- std::size_t volatile JobsRemain_ = 0;
- bool volatile JobError_ = false;
- bool volatile JobThreadsAbort_ = false;
- std::condition_variable JobsConditionRead_;
- // -- Moc meta
- std::set<std::string> MocIncludedStrings_;
- std::set<std::string> MocIncludedFiles_;
- std::set<std::string> MocAutoFiles_;
- bool volatile MocAutoFileUpdated_ = false;
- // -- Settings file
- std::string SettingsFile_;
- std::string SettingsStringMoc_;
- std::string SettingsStringUic_;
- // -- Threads and loops
- std::vector<std::unique_ptr<WorkerT>> Workers_;
-};
-
-#endif
diff --git a/Source/cmQtAutoGeneratorRcc.cxx b/Source/cmQtAutoGeneratorRcc.cxx
deleted file mode 100644
index 021a15f18..000000000
--- a/Source/cmQtAutoGeneratorRcc.cxx
+++ /dev/null
@@ -1,672 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmQtAutoGeneratorRcc.h"
-#include "cmQtAutoGen.h"
-
-#include "cmAlgorithms.h"
-#include "cmCryptoHash.h"
-#include "cmFileLockResult.h"
-#include "cmMakefile.h"
-#include "cmSystemTools.h"
-#include "cmUVHandlePtr.h"
-
-// -- Class methods
-
-cmQtAutoGeneratorRcc::cmQtAutoGeneratorRcc()
-{
- // Initialize libuv asynchronous iteration request
- UVRequest().init(*UVLoop(), &cmQtAutoGeneratorRcc::UVPollStage, this);
-}
-
-cmQtAutoGeneratorRcc::~cmQtAutoGeneratorRcc() = default;
-
-bool cmQtAutoGeneratorRcc::Init(cmMakefile* makefile)
-{
- // -- Utility lambdas
- auto InfoGet = [makefile](std::string const& key) {
- return makefile->GetSafeDefinition(key);
- };
- auto InfoGetList =
- [makefile](std::string const& key) -> std::vector<std::string> {
- std::vector<std::string> list;
- cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list);
- return list;
- };
- auto InfoGetConfig = [makefile,
- this](std::string const& key) -> std::string {
- const char* valueConf = nullptr;
- {
- std::string keyConf = key;
- keyConf += '_';
- keyConf += InfoConfig();
- valueConf = makefile->GetDefinition(keyConf);
- }
- if (valueConf == nullptr) {
- return makefile->GetSafeDefinition(key);
- }
- return std::string(valueConf);
- };
- auto InfoGetConfigList =
- [&InfoGetConfig](std::string const& key) -> std::vector<std::string> {
- std::vector<std::string> list;
- cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
- return list;
- };
-
- // -- Read info file
- if (!makefile->ReadListFile(InfoFile())) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "File processing failed");
- return false;
- }
-
- // - Configurations
- Log().RaiseVerbosity(InfoGet("ARCC_VERBOSITY"));
- MultiConfig_ = makefile->IsOn("ARCC_MULTI_CONFIG");
-
- // - Directories
- AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR");
- if (AutogenBuildDir_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Build directory empty");
- return false;
- }
-
- IncludeDir_ = InfoGetConfig("ARCC_INCLUDE_DIR");
- if (IncludeDir_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Include directory empty");
- return false;
- }
-
- // - Rcc executable
- RccExecutable_ = InfoGet("ARCC_RCC_EXECUTABLE");
- RccListOptions_ = InfoGetList("ARCC_RCC_LIST_OPTIONS");
-
- // - Job
- LockFile_ = InfoGet("ARCC_LOCK_FILE");
- QrcFile_ = InfoGet("ARCC_SOURCE");
- QrcFileName_ = cmSystemTools::GetFilenameName(QrcFile_);
- QrcFileDir_ = cmSystemTools::GetFilenamePath(QrcFile_);
- RccPathChecksum_ = InfoGet("ARCC_OUTPUT_CHECKSUM");
- RccFileName_ = InfoGet("ARCC_OUTPUT_NAME");
- Options_ = InfoGetConfigList("ARCC_OPTIONS");
- Inputs_ = InfoGetList("ARCC_INPUTS");
-
- // - Settings file
- SettingsFile_ = InfoGetConfig("ARCC_SETTINGS_FILE");
-
- // - Validity checks
- if (LockFile_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Lock file name missing");
- return false;
- }
- if (SettingsFile_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Settings file name missing");
- return false;
- }
- if (AutogenBuildDir_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(),
- "Autogen build directory missing");
- return false;
- }
- if (RccExecutable_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc executable missing");
- return false;
- }
- if (QrcFile_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc input file missing");
- return false;
- }
- if (RccFileName_.empty()) {
- Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc output file missing");
- return false;
- }
-
- // Init derived information
- // ------------------------
-
- RccFilePublic_ = AutogenBuildDir_;
- RccFilePublic_ += '/';
- RccFilePublic_ += RccPathChecksum_;
- RccFilePublic_ += '/';
- RccFilePublic_ += RccFileName_;
-
- // Compute rcc output file name
- if (IsMultiConfig()) {
- RccFileOutput_ = IncludeDir_;
- RccFileOutput_ += '/';
- RccFileOutput_ += MultiConfigOutput();
- } else {
- RccFileOutput_ = RccFilePublic_;
- }
-
- return true;
-}
-
-bool cmQtAutoGeneratorRcc::Process()
-{
- // Run libuv event loop
- UVRequest().send();
- if (uv_run(UVLoop(), UV_RUN_DEFAULT) == 0) {
- if (Error_) {
- return false;
- }
- } else {
- return false;
- }
- return true;
-}
-
-void cmQtAutoGeneratorRcc::UVPollStage(uv_async_t* handle)
-{
- reinterpret_cast<cmQtAutoGeneratorRcc*>(handle->data)->PollStage();
-}
-
-void cmQtAutoGeneratorRcc::PollStage()
-{
- switch (Stage_) {
- // -- Initialize
- case StageT::SETTINGS_READ:
- if (SettingsFileRead()) {
- SetStage(StageT::TEST_QRC_RCC_FILES);
- } else {
- SetStage(StageT::FINISH);
- }
- break;
-
- // -- Change detection
- case StageT::TEST_QRC_RCC_FILES:
- if (TestQrcRccFiles()) {
- SetStage(StageT::GENERATE);
- } else {
- SetStage(StageT::TEST_RESOURCES_READ);
- }
- break;
- case StageT::TEST_RESOURCES_READ:
- if (TestResourcesRead()) {
- SetStage(StageT::TEST_RESOURCES);
- }
- break;
- case StageT::TEST_RESOURCES:
- if (TestResources()) {
- SetStage(StageT::GENERATE);
- } else {
- SetStage(StageT::TEST_INFO_FILE);
- }
- break;
- case StageT::TEST_INFO_FILE:
- TestInfoFile();
- SetStage(StageT::GENERATE_WRAPPER);
- break;
-
- // -- Generation
- case StageT::GENERATE:
- GenerateParentDir();
- SetStage(StageT::GENERATE_RCC);
- break;
- case StageT::GENERATE_RCC:
- if (GenerateRcc()) {
- SetStage(StageT::GENERATE_WRAPPER);
- }
- break;
- case StageT::GENERATE_WRAPPER:
- GenerateWrapper();
- SetStage(StageT::SETTINGS_WRITE);
- break;
-
- // -- Finalize
- case StageT::SETTINGS_WRITE:
- SettingsFileWrite();
- SetStage(StageT::FINISH);
- break;
- case StageT::FINISH:
- // Clear all libuv handles
- UVRequest().reset();
- // Set highest END stage manually
- Stage_ = StageT::END;
- break;
- case StageT::END:
- break;
- }
-}
-
-void cmQtAutoGeneratorRcc::SetStage(StageT stage)
-{
- if (Error_) {
- stage = StageT::FINISH;
- }
- // Only allow to increase the stage
- if (Stage_ < stage) {
- Stage_ = stage;
- UVRequest().send();
- }
-}
-
-std::string cmQtAutoGeneratorRcc::MultiConfigOutput() const
-{
- static std::string const suffix = "_CMAKE_";
- std::string res;
- res += RccPathChecksum_;
- res += '/';
- res += AppendFilenameSuffix(RccFileName_, suffix);
- return res;
-}
-
-bool cmQtAutoGeneratorRcc::SettingsFileRead()
-{
- // Compose current settings strings
- {
- cmCryptoHash crypt(cmCryptoHash::AlgoSHA256);
- std::string const sep(" ~~~ ");
- {
- std::string str;
- str += RccExecutable_;
- str += sep;
- str += cmJoin(RccListOptions_, ";");
- str += sep;
- str += QrcFile_;
- str += sep;
- str += RccPathChecksum_;
- str += sep;
- str += RccFileName_;
- str += sep;
- str += cmJoin(Options_, ";");
- str += sep;
- str += cmJoin(Inputs_, ";");
- str += sep;
- SettingsString_ = crypt.HashString(str);
- }
- }
-
- // Make sure the settings file exists
- if (!FileSys().FileExists(SettingsFile_, true)) {
- // Touch the settings file to make sure it exists
- FileSys().Touch(SettingsFile_, true);
- }
-
- // Lock the lock file
- {
- // Make sure the lock file exists
- if (!FileSys().FileExists(LockFile_, true)) {
- if (!FileSys().Touch(LockFile_, true)) {
- Log().ErrorFile(GeneratorT::RCC, LockFile_,
- "Lock file creation failed");
- Error_ = true;
- return false;
- }
- }
- // Lock the lock file
- cmFileLockResult lockResult =
- LockFileLock_.Lock(LockFile_, static_cast<unsigned long>(-1));
- if (!lockResult.IsOk()) {
- Log().ErrorFile(GeneratorT::RCC, LockFile_,
- "File lock failed: " + lockResult.GetOutputMessage());
- Error_ = true;
- return false;
- }
- }
-
- // Read old settings
- {
- std::string content;
- if (FileSys().FileRead(content, SettingsFile_)) {
- SettingsChanged_ = (SettingsString_ != SettingsFind(content, "rcc"));
- // In case any setting changed clear the old settings file.
- // This triggers a full rebuild on the next run if the current
- // build is aborted before writing the current settings in the end.
- if (SettingsChanged_) {
- FileSys().FileWrite(GeneratorT::RCC, SettingsFile_, "");
- }
- } else {
- SettingsChanged_ = true;
- }
- }
-
- return true;
-}
-
-void cmQtAutoGeneratorRcc::SettingsFileWrite()
-{
- // Only write if any setting changed
- if (SettingsChanged_) {
- if (Log().Verbose()) {
- Log().Info(GeneratorT::RCC,
- "Writing settings file " + Quoted(SettingsFile_));
- }
- // Write settings file
- std::string content = "rcc:";
- content += SettingsString_;
- content += '\n';
- if (!FileSys().FileWrite(GeneratorT::RCC, SettingsFile_, content)) {
- Log().ErrorFile(GeneratorT::RCC, SettingsFile_,
- "Settings file writing failed");
- // Remove old settings file to trigger a full rebuild on the next run
- FileSys().FileRemove(SettingsFile_);
- Error_ = true;
- }
- }
-
- // Unlock the lock file
- LockFileLock_.Release();
-}
-
-bool cmQtAutoGeneratorRcc::TestQrcRccFiles()
-{
- // Do basic checks if rcc generation is required
-
- // Test if the rcc output file exists
- if (!FileSys().FileExists(RccFileOutput_)) {
- if (Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(RccFileOutput_);
- reason += " from its source file ";
- reason += Quoted(QrcFile_);
- reason += " because it doesn't exist";
- Log().Info(GeneratorT::RCC, reason);
- }
- Generate_ = true;
- return Generate_;
- }
-
- // Test if the settings changed
- if (SettingsChanged_) {
- if (Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(RccFileOutput_);
- reason += " from ";
- reason += Quoted(QrcFile_);
- reason += " because the RCC settings changed";
- Log().Info(GeneratorT::RCC, reason);
- }
- Generate_ = true;
- return Generate_;
- }
-
- // Test if the rcc output file is older than the .qrc file
- {
- bool isOlder = false;
- {
- std::string error;
- isOlder = FileSys().FileIsOlderThan(RccFileOutput_, QrcFile_, &error);
- if (!error.empty()) {
- Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
- Error_ = true;
- }
- }
- if (isOlder) {
- if (Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(RccFileOutput_);
- reason += " because it is older than ";
- reason += Quoted(QrcFile_);
- Log().Info(GeneratorT::RCC, reason);
- }
- Generate_ = true;
- }
- }
-
- return Generate_;
-}
-
-bool cmQtAutoGeneratorRcc::TestResourcesRead()
-{
- if (!Inputs_.empty()) {
- // Inputs are known already
- return true;
- }
-
- if (!RccListOptions_.empty()) {
- // Start a rcc list process and parse the output
- if (Process_) {
- // Process is running already
- if (Process_->IsFinished()) {
- // Process is finished
- if (!ProcessResult_.error()) {
- // Process success
- std::string parseError;
- if (!RccListParseOutput(ProcessResult_.StdOut, ProcessResult_.StdErr,
- Inputs_, parseError)) {
- Log().ErrorFile(GeneratorT::RCC, QrcFile_, parseError);
- Error_ = true;
- }
- } else {
- Log().ErrorFile(GeneratorT::RCC, QrcFile_,
- ProcessResult_.ErrorMessage);
- Error_ = true;
- }
- // Clean up
- Process_.reset();
- ProcessResult_.reset();
- } else {
- // Process is not finished, yet.
- return false;
- }
- } else {
- // Start a new process
- // rcc prints relative entry paths when started in the directory of the
- // qrc file with a pathless qrc file name argument.
- // This is important because on Windows absolute paths returned by rcc
- // might contain bad multibyte characters when the qrc file path
- // contains non-ASCII pcharacters.
- std::vector<std::string> cmd;
- cmd.push_back(RccExecutable_);
- cmd.insert(cmd.end(), RccListOptions_.begin(), RccListOptions_.end());
- cmd.push_back(QrcFileName_);
- // We're done here if the process fails to start
- return !StartProcess(QrcFileDir_, cmd, false);
- }
- } else {
- // rcc does not support the --list command.
- // Read the qrc file content and parse it.
- std::string qrcContent;
- if (FileSys().FileRead(GeneratorT::RCC, qrcContent, QrcFile_)) {
- RccListParseContent(qrcContent, Inputs_);
- }
- }
-
- if (!Inputs_.empty()) {
- // Convert relative paths to absolute paths
- RccListConvertFullPath(QrcFileDir_, Inputs_);
- }
-
- return true;
-}
-
-bool cmQtAutoGeneratorRcc::TestResources()
-{
- if (Inputs_.empty()) {
- return true;
- }
- {
- std::string error;
- for (std::string const& resFile : Inputs_) {
- // Check if the resource file exists
- if (!FileSys().FileExists(resFile)) {
- error = "Could not find the resource file\n ";
- error += Quoted(resFile);
- error += '\n';
- Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
- Error_ = true;
- break;
- }
- // Check if the resource file is newer than the build file
- if (FileSys().FileIsOlderThan(RccFileOutput_, resFile, &error)) {
- if (Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(RccFileOutput_);
- reason += " from ";
- reason += Quoted(QrcFile_);
- reason += " because it is older than ";
- reason += Quoted(resFile);
- Log().Info(GeneratorT::RCC, reason);
- }
- Generate_ = true;
- break;
- }
- // Print error and break on demand
- if (!error.empty()) {
- Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
- Error_ = true;
- break;
- }
- }
- }
-
- return Generate_;
-}
-
-void cmQtAutoGeneratorRcc::TestInfoFile()
-{
- // Test if the rcc output file is older than the info file
- {
- bool isOlder = false;
- {
- std::string error;
- isOlder = FileSys().FileIsOlderThan(RccFileOutput_, InfoFile(), &error);
- if (!error.empty()) {
- Log().ErrorFile(GeneratorT::RCC, QrcFile_, error);
- Error_ = true;
- }
- }
- if (isOlder) {
- if (Log().Verbose()) {
- std::string reason = "Touching ";
- reason += Quoted(RccFileOutput_);
- reason += " because it is older than ";
- reason += Quoted(InfoFile());
- Log().Info(GeneratorT::RCC, reason);
- }
- // Touch build file
- FileSys().Touch(RccFileOutput_);
- BuildFileChanged_ = true;
- }
- }
-}
-
-void cmQtAutoGeneratorRcc::GenerateParentDir()
-{
- // Make sure the parent directory exists
- if (!FileSys().MakeParentDirectory(GeneratorT::RCC, RccFileOutput_)) {
- Error_ = true;
- }
-}
-
-/**
- * @return True when finished
- */
-bool cmQtAutoGeneratorRcc::GenerateRcc()
-{
- if (!Generate_) {
- // Nothing to do
- return true;
- }
-
- if (Process_) {
- // Process is running already
- if (Process_->IsFinished()) {
- // Process is finished
- if (!ProcessResult_.error()) {
- // Rcc process success
- // Print rcc output
- if (!ProcessResult_.StdOut.empty()) {
- Log().Info(GeneratorT::RCC, ProcessResult_.StdOut);
- }
- BuildFileChanged_ = true;
- } else {
- // Rcc process failed
- {
- std::string emsg = "The rcc process failed to compile\n ";
- emsg += Quoted(QrcFile_);
- emsg += "\ninto\n ";
- emsg += Quoted(RccFileOutput_);
- if (ProcessResult_.error()) {
- emsg += "\n";
- emsg += ProcessResult_.ErrorMessage;
- }
- Log().ErrorCommand(GeneratorT::RCC, emsg, Process_->Setup().Command,
- ProcessResult_.StdOut);
- }
- FileSys().FileRemove(RccFileOutput_);
- Error_ = true;
- }
- // Clean up
- Process_.reset();
- ProcessResult_.reset();
- } else {
- // Process is not finished, yet.
- return false;
- }
- } else {
- // Start a rcc process
- std::vector<std::string> cmd;
- cmd.push_back(RccExecutable_);
- cmd.insert(cmd.end(), Options_.begin(), Options_.end());
- cmd.emplace_back("-o");
- cmd.push_back(RccFileOutput_);
- cmd.push_back(QrcFile_);
- // We're done here if the process fails to start
- return !StartProcess(AutogenBuildDir_, cmd, true);
- }
-
- return true;
-}
-
-void cmQtAutoGeneratorRcc::GenerateWrapper()
-{
- // Generate a wrapper source file on demand
- if (IsMultiConfig()) {
- // Wrapper file content
- std::string content;
- content += "// This is an autogenerated configuration wrapper file.\n";
- content += "// Changes will be overwritten.\n";
- content += "#include <";
- content += MultiConfigOutput();
- content += ">\n";
-
- // Write content to file
- if (FileSys().FileDiffers(RccFilePublic_, content)) {
- // Write new wrapper file
- if (Log().Verbose()) {
- Log().Info(GeneratorT::RCC,
- "Generating RCC wrapper file " + RccFilePublic_);
- }
- if (!FileSys().FileWrite(GeneratorT::RCC, RccFilePublic_, content)) {
- Log().ErrorFile(GeneratorT::RCC, RccFilePublic_,
- "RCC wrapper file writing failed");
- Error_ = true;
- }
- } else if (BuildFileChanged_) {
- // Just touch the wrapper file
- if (Log().Verbose()) {
- Log().Info(GeneratorT::RCC,
- "Touching RCC wrapper file " + RccFilePublic_);
- }
- FileSys().Touch(RccFilePublic_);
- }
- }
-}
-
-bool cmQtAutoGeneratorRcc::StartProcess(
- std::string const& workingDirectory, std::vector<std::string> const& command,
- bool mergedOutput)
-{
- // Log command
- if (Log().Verbose()) {
- std::string msg = "Running command:\n";
- msg += QuotedCommand(command);
- msg += '\n';
- Log().Info(GeneratorT::RCC, msg);
- }
-
- // Create process handler
- Process_ = cm::make_unique<ReadOnlyProcessT>();
- Process_->setup(&ProcessResult_, mergedOutput, command, workingDirectory);
- // Start process
- if (!Process_->start(UVLoop(), [this] { UVRequest().send(); })) {
- Log().ErrorFile(GeneratorT::RCC, QrcFile_, ProcessResult_.ErrorMessage);
- Error_ = true;
- // Clean up
- Process_.reset();
- ProcessResult_.reset();
- return false;
- }
- return true;
-}
diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx
new file mode 100644
index 000000000..889f47db1
--- /dev/null
+++ b/Source/cmQtAutoMocUic.cxx
@@ -0,0 +1,2193 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmQtAutoMocUic.h"
+
+#include <algorithm>
+#include <array>
+#include <list>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <utility>
+
+#include "cmAlgorithms.h"
+#include "cmCryptoHash.h"
+#include "cmGeneratedFileStream.h"
+#include "cmMakefile.h"
+#include "cmQtAutoGen.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+#include "cmsys/FStream.hxx"
+
+#if defined(__APPLE__)
+# include <unistd.h>
+#endif
+
+static constexpr std::size_t MocUnderscoreLength = 4; // Length of "moc_"
+static constexpr std::size_t UiUnderscoreLength = 3; // Length of "ui_"
+
+cmQtAutoMocUic::IncludeKeyT::IncludeKeyT(std::string const& key,
+ std::size_t basePrefixLength)
+ : Key(key)
+ , Dir(SubDirPrefix(key))
+ , Base(cmSystemTools::GetFilenameWithoutLastExtension(key))
+{
+ if (basePrefixLength != 0) {
+ Base = Base.substr(basePrefixLength);
+ }
+}
+
+void cmQtAutoMocUic::ParseCacheT::FileT::Clear()
+{
+ Moc.Macro.clear();
+ Moc.Include.Underscore.clear();
+ Moc.Include.Dot.clear();
+ Moc.Depends.clear();
+
+ Uic.Include.clear();
+ Uic.Depends.clear();
+}
+
+cmQtAutoMocUic::ParseCacheT::FileHandleT cmQtAutoMocUic::ParseCacheT::Get(
+ std::string const& fileName) const
+{
+ auto it = Map_.find(fileName);
+ if (it != Map_.end()) {
+ return it->second;
+ }
+ return FileHandleT();
+}
+
+cmQtAutoMocUic::ParseCacheT::GetOrInsertT
+cmQtAutoMocUic::ParseCacheT::GetOrInsert(std::string const& fileName)
+{
+ // Find existing entry
+ {
+ auto it = Map_.find(fileName);
+ if (it != Map_.end()) {
+ return GetOrInsertT{ it->second, false };
+ }
+ }
+
+ // Insert new entry
+ return GetOrInsertT{
+ Map_.emplace(fileName, std::make_shared<FileT>()).first->second, true
+ };
+}
+
+cmQtAutoMocUic::ParseCacheT::ParseCacheT() = default;
+cmQtAutoMocUic::ParseCacheT::~ParseCacheT() = default;
+
+void cmQtAutoMocUic::ParseCacheT::Clear()
+{
+ Map_.clear();
+}
+
+bool cmQtAutoMocUic::ParseCacheT::ReadFromFile(std::string const& fileName)
+{
+ cmsys::ifstream fin(fileName.c_str());
+ if (!fin) {
+ return false;
+ }
+ FileHandleT fileHandle;
+
+ std::string line;
+ while (std::getline(fin, line)) {
+ // Check if this an empty or a comment line
+ if (line.empty() || line.front() == '#') {
+ continue;
+ }
+ // Drop carriage return character at the end
+ if (line.back() == '\r') {
+ line.pop_back();
+ if (line.empty()) {
+ continue;
+ }
+ }
+ // Check if this a file name line
+ if (line.front() != ' ') {
+ fileHandle = GetOrInsert(line).first;
+ continue;
+ }
+
+ // Bad line or bad file handle
+ if (!fileHandle || (line.size() < 6)) {
+ continue;
+ }
+
+ constexpr std::size_t offset = 5;
+ if (cmHasLiteralPrefix(line, " mmc:")) {
+ fileHandle->Moc.Macro = line.substr(offset);
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " miu:")) {
+ fileHandle->Moc.Include.Underscore.emplace_back(line.substr(offset),
+ MocUnderscoreLength);
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " mid:")) {
+ fileHandle->Moc.Include.Dot.emplace_back(line.substr(offset), 0);
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " mdp:")) {
+ fileHandle->Moc.Depends.emplace_back(line.substr(offset));
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " uic:")) {
+ fileHandle->Uic.Include.emplace_back(line.substr(offset),
+ UiUnderscoreLength);
+ continue;
+ }
+ if (cmHasLiteralPrefix(line, " udp:")) {
+ fileHandle->Uic.Depends.emplace_back(line.substr(offset));
+ continue;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoMocUic::ParseCacheT::WriteToFile(std::string const& fileName)
+{
+ cmGeneratedFileStream ofs(fileName);
+ if (!ofs) {
+ return false;
+ }
+ ofs << "# Generated by CMake. Changes will be overwritten." << std::endl;
+ for (auto const& pair : Map_) {
+ ofs << pair.first << std::endl;
+ FileT const& file = *pair.second;
+ if (!file.Moc.Macro.empty()) {
+ ofs << " mmc:" << file.Moc.Macro << std::endl;
+ }
+ for (IncludeKeyT const& item : file.Moc.Include.Underscore) {
+ ofs << " miu:" << item.Key << std::endl;
+ }
+ for (IncludeKeyT const& item : file.Moc.Include.Dot) {
+ ofs << " mid:" << item.Key << std::endl;
+ }
+ for (std::string const& item : file.Moc.Depends) {
+ ofs << " mdp:" << item << std::endl;
+ }
+ for (IncludeKeyT const& item : file.Uic.Include) {
+ ofs << " uic:" << item.Key << std::endl;
+ }
+ for (std::string const& item : file.Uic.Depends) {
+ ofs << " udp:" << item << std::endl;
+ }
+ }
+ return ofs.Close();
+}
+
+cmQtAutoMocUic::BaseSettingsT::BaseSettingsT() = default;
+cmQtAutoMocUic::BaseSettingsT::~BaseSettingsT() = default;
+
+cmQtAutoMocUic::MocSettingsT::MocSettingsT()
+{
+ RegExpInclude.compile(
+ "(^|\n)[ \t]*#[ \t]*include[ \t]+"
+ "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
+}
+
+cmQtAutoMocUic::MocSettingsT::~MocSettingsT() = default;
+
+bool cmQtAutoMocUic::MocSettingsT::skipped(std::string const& fileName) const
+{
+ return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
+}
+
+std::string cmQtAutoMocUic::MocSettingsT::MacrosString() const
+{
+ std::string res;
+ const auto itB = MacroFilters.cbegin();
+ const auto itE = MacroFilters.cend();
+ const auto itL = itE - 1;
+ auto itC = itB;
+ for (; itC != itE; ++itC) {
+ // Separator
+ if (itC != itB) {
+ if (itC != itL) {
+ res += ", ";
+ } else {
+ res += " or ";
+ }
+ }
+ // Key
+ res += itC->Key;
+ }
+ return res;
+}
+
+cmQtAutoMocUic::UicSettingsT::UicSettingsT()
+{
+ RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+"
+ "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
+}
+
+cmQtAutoMocUic::UicSettingsT::~UicSettingsT() = default;
+
+bool cmQtAutoMocUic::UicSettingsT::skipped(std::string const& fileName) const
+{
+ return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
+}
+
+void cmQtAutoMocUic::JobT::LogError(GenT genType,
+ std::string const& message) const
+{
+ Gen()->AbortError();
+ Gen()->Log().Error(genType, message);
+}
+
+void cmQtAutoMocUic::JobT::LogFileError(GenT genType,
+ std::string const& filename,
+ std::string const& message) const
+{
+ Gen()->AbortError();
+ Gen()->Log().ErrorFile(genType, filename, message);
+}
+
+void cmQtAutoMocUic::JobT::LogCommandError(
+ GenT genType, std::string const& message,
+ std::vector<std::string> const& command, std::string const& output) const
+{
+ Gen()->AbortError();
+ Gen()->Log().ErrorCommand(genType, message, command, output);
+}
+
+bool cmQtAutoMocUic::JobT::RunProcess(GenT genType,
+ cmWorkerPool::ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string* infoMessage)
+{
+ // Log command
+ if (Log().Verbose()) {
+ std::string msg;
+ if ((infoMessage != nullptr) && !infoMessage->empty()) {
+ msg = *infoMessage;
+ if (msg.back() != '\n') {
+ msg += '\n';
+ }
+ }
+ msg += QuotedCommand(command);
+ msg += '\n';
+ Log().Info(genType, msg);
+ }
+ return cmWorkerPool::JobT::RunProcess(result, command,
+ BaseConst().AutogenBuildDir);
+}
+
+void cmQtAutoMocUic::JobMocPredefsT::Process()
+{
+ // (Re)generate moc_predefs.h on demand
+ std::unique_ptr<std::string> reason;
+ if (Log().Verbose()) {
+ reason = cm::make_unique<std::string>();
+ }
+ if (!Update(reason.get())) {
+ return;
+ }
+ std::string const& predefsFileRel = MocConst().PredefsFileRel;
+ std::string const& predefsFileAbs = MocConst().PredefsFileAbs;
+ {
+ cmWorkerPool::ProcessResultT result;
+ {
+ // Compose command
+ std::vector<std::string> cmd = MocConst().PredefsCmd;
+ // Add includes
+ cmAppend(cmd, MocConst().Includes);
+ // Add definitions
+ for (std::string const& def : MocConst().Definitions) {
+ cmd.emplace_back("-D" + def);
+ }
+ // Execute command
+ if (!RunProcess(GenT::MOC, result, cmd, reason.get())) {
+ std::string msg = "The content generation command for ";
+ msg += Quoted(predefsFileRel);
+ msg += " failed.\n";
+ msg += result.ErrorMessage;
+ LogCommandError(GenT::MOC, msg, cmd, result.StdOut);
+ return;
+ }
+ }
+
+ // (Re)write predefs file only on demand
+ if (cmQtAutoGenerator::FileDiffers(predefsFileAbs, result.StdOut)) {
+ if (!cmQtAutoGenerator::FileWrite(predefsFileAbs, result.StdOut)) {
+ std::string msg = "Writing ";
+ msg += Quoted(predefsFileRel);
+ msg += " failed.";
+ LogFileError(GenT::MOC, predefsFileAbs, msg);
+ return;
+ }
+ } else {
+ // Touch to update the time stamp
+ if (Log().Verbose()) {
+ Log().Info(GenT::MOC, "Touching " + Quoted(predefsFileRel));
+ }
+ if (!cmSystemTools::Touch(predefsFileAbs, false)) {
+ std::string msg = "Touching ";
+ msg += Quoted(predefsFileAbs);
+ msg += " failed.";
+ LogFileError(GenT::MOC, predefsFileAbs, msg);
+ return;
+ }
+ }
+ }
+
+ // Read file time afterwards
+ if (!MocEval().PredefsTime.Load(predefsFileAbs)) {
+ LogFileError(GenT::MOC, predefsFileAbs, "File time reading failed.");
+ return;
+ }
+}
+
+bool cmQtAutoMocUic::JobMocPredefsT::Update(std::string* reason) const
+{
+ // Test if the file exists
+ if (!MocEval().PredefsTime.Load(MocConst().PredefsFileAbs)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(MocConst().PredefsFileRel);
+ *reason += ", because it doesn't exist.";
+ }
+ return true;
+ }
+
+ // Test if the settings changed
+ if (MocConst().SettingsChanged) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(MocConst().PredefsFileRel);
+ *reason += ", because the moc settings changed.";
+ }
+ return true;
+ }
+
+ // Test if the executable is newer
+ {
+ std::string const& exec = MocConst().PredefsCmd.at(0);
+ cmFileTime execTime;
+ if (execTime.Load(exec)) {
+ if (MocEval().PredefsTime.Older(execTime)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(MocConst().PredefsFileRel);
+ *reason += " because it is older than ";
+ *reason += Quoted(exec);
+ *reason += ".";
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool cmQtAutoMocUic::JobParseT::ReadFile()
+{
+ // Clear old parse information
+ FileHandle->ParseData->Clear();
+ std::string const& fileName = FileHandle->FileName;
+ // Write info
+ if (Log().Verbose()) {
+ Log().Info(GenT::GEN, "Parsing " + Quoted(fileName));
+ }
+ // Read file content
+ {
+ std::string error;
+ if (!cmQtAutoGenerator::FileRead(Content, fileName, &error)) {
+ LogFileError(GenT::GEN, fileName, "Could not read the file: " + error);
+ return false;
+ }
+ }
+ // Warn if empty
+ if (Content.empty()) {
+ Log().WarningFile(GenT::GEN, fileName, "The file is empty.");
+ return false;
+ }
+ return true;
+}
+
+void cmQtAutoMocUic::JobParseT::CreateKeys(std::vector<IncludeKeyT>& container,
+ std::set<std::string> const& source,
+ std::size_t basePrefixLength)
+{
+ if (source.empty()) {
+ return;
+ }
+ container.reserve(source.size());
+ for (std::string const& src : source) {
+ container.emplace_back(src, basePrefixLength);
+ }
+}
+
+void cmQtAutoMocUic::JobParseT::MocMacro()
+{
+ for (KeyExpT const& filter : MocConst().MacroFilters) {
+ // Run a simple find string check
+ if (Content.find(filter.Key) == std::string::npos) {
+ continue;
+ }
+ // Run the expensive regular expression check loop
+ cmsys::RegularExpressionMatch match;
+ if (filter.Exp.find(Content.c_str(), match)) {
+ // Keep detected macro name
+ FileHandle->ParseData->Moc.Macro = filter.Key;
+ return;
+ }
+ }
+}
+
+void cmQtAutoMocUic::JobParseT::MocDependecies()
+{
+ if (MocConst().DependFilters.empty()) {
+ return;
+ }
+
+ // Find dependency strings
+ std::set<std::string> parseDepends;
+ for (KeyExpT const& filter : MocConst().DependFilters) {
+ // Run a simple find string check
+ if (Content.find(filter.Key) == std::string::npos) {
+ continue;
+ }
+ // Run the expensive regular expression check loop
+ const char* contentChars = Content.c_str();
+ cmsys::RegularExpressionMatch match;
+ while (filter.Exp.find(contentChars, match)) {
+ {
+ std::string dep = match.match(1);
+ if (!dep.empty()) {
+ parseDepends.emplace(std::move(dep));
+ }
+ }
+ contentChars += match.end();
+ }
+ }
+
+ // Store dependency strings
+ {
+ auto& Depends = FileHandle->ParseData->Moc.Depends;
+ Depends.reserve(parseDepends.size());
+ for (std::string const& item : parseDepends) {
+ Depends.emplace_back(item);
+ // Replace end of line characters in filenames
+ std::string& path = Depends.back();
+ std::replace(path.begin(), path.end(), '\n', ' ');
+ std::replace(path.begin(), path.end(), '\r', ' ');
+ }
+ }
+}
+
+void cmQtAutoMocUic::JobParseT::MocIncludes()
+{
+ if (Content.find("moc") == std::string::npos) {
+ return;
+ }
+
+ std::set<std::string> underscore;
+ std::set<std::string> dot;
+ {
+ const char* contentChars = Content.c_str();
+ cmsys::RegularExpression const& regExp = MocConst().RegExpInclude;
+ cmsys::RegularExpressionMatch match;
+ while (regExp.find(contentChars, match)) {
+ std::string incString = match.match(2);
+ std::string const incBase =
+ cmSystemTools::GetFilenameWithoutLastExtension(incString);
+ if (cmHasLiteralPrefix(incBase, "moc_")) {
+ // moc_<BASE>.cpp
+ // Remove the moc_ part from the base name
+ underscore.emplace(std::move(incString));
+ } else {
+ // <BASE>.moc
+ dot.emplace(std::move(incString));
+ }
+ // Forward content pointer
+ contentChars += match.end();
+ }
+ }
+ auto& Include = FileHandle->ParseData->Moc.Include;
+ CreateKeys(Include.Underscore, underscore, MocUnderscoreLength);
+ CreateKeys(Include.Dot, dot, 0);
+}
+
+void cmQtAutoMocUic::JobParseT::UicIncludes()
+{
+ if (Content.find("ui_") == std::string::npos) {
+ return;
+ }
+
+ std::set<std::string> includes;
+ {
+ const char* contentChars = Content.c_str();
+ cmsys::RegularExpression const& regExp = UicConst().RegExpInclude;
+ cmsys::RegularExpressionMatch match;
+ while (regExp.find(contentChars, match)) {
+ includes.emplace(match.match(2));
+ // Forward content pointer
+ contentChars += match.end();
+ }
+ }
+ CreateKeys(FileHandle->ParseData->Uic.Include, includes, UiUnderscoreLength);
+}
+
+void cmQtAutoMocUic::JobParseHeaderT::Process()
+{
+ if (!ReadFile()) {
+ return;
+ }
+ // Moc parsing
+ if (FileHandle->Moc) {
+ MocMacro();
+ MocDependecies();
+ }
+ // Uic parsing
+ if (FileHandle->Uic) {
+ UicIncludes();
+ }
+}
+
+void cmQtAutoMocUic::JobParseSourceT::Process()
+{
+ if (!ReadFile()) {
+ return;
+ }
+ // Moc parsing
+ if (FileHandle->Moc) {
+ MocMacro();
+ MocDependecies();
+ MocIncludes();
+ }
+ // Uic parsing
+ if (FileHandle->Uic) {
+ UicIncludes();
+ }
+}
+
+void cmQtAutoMocUic::JobEvaluateT::Process()
+{
+ // Evaluate for moc
+ if (MocConst().Enabled) {
+ // Evaluate headers
+ for (auto const& pair : BaseEval().Headers) {
+ if (!MocEvalHeader(pair.second)) {
+ return;
+ }
+ }
+ // Evaluate sources
+ for (auto const& pair : BaseEval().Sources) {
+ if (!MocEvalSource(pair.second)) {
+ return;
+ }
+ }
+ }
+ // Evaluate for uic
+ if (UicConst().Enabled) {
+ if (!UicEval(BaseEval().Headers) || !UicEval(BaseEval().Sources)) {
+ return;
+ }
+ }
+
+ // Add discovered header parse jobs
+ Gen()->CreateParseJobs<JobParseHeaderT>(MocEval().HeadersDiscovered);
+ // Add generate job after
+ Gen()->WorkerPool().EmplaceJob<JobGenerateT>();
+}
+
+bool cmQtAutoMocUic::JobEvaluateT::MocEvalHeader(SourceFileHandleT source)
+{
+ SourceFileT const& sourceFile = *source;
+ auto const& parseData = sourceFile.ParseData->Moc;
+ if (!source->Moc) {
+ return true;
+ }
+
+ if (!parseData.Macro.empty()) {
+ // Create a new mapping
+ MappingHandleT handle = std::make_shared<MappingT>();
+ handle->SourceFile = std::move(source);
+
+ // Absolute build path
+ if (BaseConst().MultiConfig) {
+ handle->OutputFile = Gen()->AbsoluteIncludePath(sourceFile.BuildPath);
+ } else {
+ handle->OutputFile = Gen()->AbsoluteBuildPath(sourceFile.BuildPath);
+ }
+
+ // Register mapping in headers map
+ MocRegisterMapping(handle, true);
+ }
+
+ return true;
+}
+
+bool cmQtAutoMocUic::JobEvaluateT::MocEvalSource(
+ SourceFileHandleT const& source)
+{
+ SourceFileT const& sourceFile = *source;
+ auto const& parseData = sourceFile.ParseData->Moc;
+ if (!sourceFile.Moc ||
+ (parseData.Macro.empty() && parseData.Include.Underscore.empty() &&
+ parseData.Include.Dot.empty())) {
+ return true;
+ }
+
+ std::string const sourceDir = SubDirPrefix(sourceFile.FileName);
+ std::string const sourceBase =
+ cmSystemTools::GetFilenameWithoutLastExtension(sourceFile.FileName);
+
+ // For relaxed mode check if the own "moc_" or ".moc" file is included
+ bool const relaxedMode = MocConst().RelaxedMode;
+ bool sourceIncludesMocUnderscore = false;
+ bool sourceIncludesDotMoc = false;
+ // Check if the sources own "moc_" or ".moc" file is included
+ if (relaxedMode) {
+ for (IncludeKeyT const& incKey : parseData.Include.Underscore) {
+ if (incKey.Base == sourceBase) {
+ sourceIncludesMocUnderscore = true;
+ break;
+ }
+ }
+ }
+ for (IncludeKeyT const& incKey : parseData.Include.Dot) {
+ if (incKey.Base == sourceBase) {
+ sourceIncludesDotMoc = true;
+ break;
+ }
+ }
+
+ // Check if this source needs to be moc processed but doesn't.
+ if (!sourceIncludesDotMoc && !parseData.Macro.empty() &&
+ !(relaxedMode && sourceIncludesMocUnderscore)) {
+ {
+ std::string emsg = "The file contains a ";
+ emsg += Quoted(parseData.Macro);
+ emsg += " macro, but does not include ";
+ emsg += Quoted(sourceBase + ".moc");
+ emsg += "!\nConsider to\n - add #include \"";
+ emsg += sourceBase;
+ emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file";
+ LogFileError(GenT::MOC, sourceFile.FileName, emsg);
+ }
+ return false;
+ }
+
+ // Evaluate "moc_" includes
+ for (IncludeKeyT const& incKey : parseData.Include.Underscore) {
+ std::string const headerBase = incKey.Dir + incKey.Base;
+ SourceFileHandleT header = MocFindIncludedHeader(sourceDir, headerBase);
+ if (!header) {
+ {
+ std::string msg = "The file includes the moc file ";
+ msg += Quoted(incKey.Key);
+ msg += ",\nbut the header could not be found "
+ "in the following locations\n";
+ msg += MocMessageTestHeaders(headerBase);
+ LogFileError(GenT::MOC, sourceFile.FileName, msg);
+ }
+ return false;
+ }
+ // The include might be handled differently in relaxed mode
+ if (relaxedMode && !sourceIncludesDotMoc && !parseData.Macro.empty() &&
+ (incKey.Base == sourceBase)) {
+ // The <BASE>.cpp file includes a Qt macro but does not include the
+ // <BASE>.moc file. In this case, the moc_<BASE>.cpp should probably
+ // be generated from <BASE>.cpp instead of <BASE>.h, because otherwise
+ // it won't build. But warn, since this is not how it is supposed to be
+ // used. This is for KDE4 compatibility.
+ {
+ // Issue a warning
+ std::string msg = "The file contains a ";
+ msg += Quoted(parseData.Macro);
+ msg += " macro, but does not include ";
+ msg += Quoted(sourceBase + ".moc");
+ msg += ".\nInstead it includes ";
+ msg += Quoted(incKey.Key);
+ msg += ".\nRunning moc on the source\n ";
+ msg += Quoted(sourceFile.FileName);
+ msg += "!\nBetter include ";
+ msg += Quoted(sourceBase + ".moc");
+ msg += " for compatibility with regular mode.\n";
+ msg += "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n";
+ Log().WarningFile(GenT::MOC, sourceFile.FileName, msg);
+ }
+ // Create mapping
+ if (!MocRegisterIncluded(incKey.Key, source, source, false)) {
+ return false;
+ }
+ continue;
+ }
+
+ // Check if header is skipped
+ if (MocConst().skipped(header->FileName)) {
+ continue;
+ }
+ // Create mapping
+ if (!MocRegisterIncluded(incKey.Key, source, std::move(header), true)) {
+ return false;
+ }
+ }
+
+ // Evaluate ".moc" includes
+ if (relaxedMode) {
+ // Relaxed mode
+ for (IncludeKeyT const& incKey : parseData.Include.Dot) {
+ // Check if this is the sources own .moc file
+ bool const ownMoc = (incKey.Base == sourceBase);
+ if (ownMoc && !parseData.Macro.empty()) {
+ // Create mapping for the regular use case
+ if (!MocRegisterIncluded(incKey.Key, source, source, false)) {
+ return false;
+ }
+ continue;
+ }
+ // Try to find a header instead but issue a warning.
+ // This is for KDE4 compatibility.
+ std::string const headerBase = incKey.Dir + incKey.Base;
+ SourceFileHandleT header = MocFindIncludedHeader(sourceDir, headerBase);
+ if (!header) {
+ std::string msg = "The file includes the moc file ";
+ msg += Quoted(incKey.Key);
+ msg += ",\nwhich seems to be the moc file from a different source "
+ "file.\nCMAKE_AUTOMOC_RELAXED_MODE: Also a matching header"
+ "could not be found in the following locations\n";
+ msg += MocMessageTestHeaders(headerBase);
+ LogFileError(GenT::MOC, sourceFile.FileName, msg);
+ return false;
+ }
+ // Check if header is skipped
+ if (MocConst().skipped(header->FileName)) {
+ continue;
+ }
+ // Issue a warning
+ if (ownMoc && parseData.Macro.empty()) {
+ std::string msg = "The file includes the moc file ";
+ msg += Quoted(incKey.Key);
+ msg += ", but does not contain a\n";
+ msg += MocConst().MacrosString();
+ msg += " macro.\nRunning moc on the header\n ";
+ msg += Quoted(header->FileName);
+ msg += "!\nBetter include ";
+ msg += Quoted("moc_" + incKey.Base + ".cpp");
+ msg += " for a compatibility with regular mode.\n";
+ msg += "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n";
+ Log().WarningFile(GenT::MOC, sourceFile.FileName, msg);
+ } else {
+ std::string msg = "The file includes the moc file ";
+ msg += Quoted(incKey.Key);
+ msg += " instead of ";
+ msg += Quoted("moc_" + incKey.Base + ".cpp");
+ msg += ".\nRunning moc on the header\n ";
+ msg += Quoted(header->FileName);
+ msg += "!\nBetter include ";
+ msg += Quoted("moc_" + incKey.Base + ".cpp");
+ msg += " for compatibility with regular mode.\n";
+ msg += "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n";
+ Log().WarningFile(GenT::MOC, sourceFile.FileName, msg);
+ }
+ // Create mapping
+ if (!MocRegisterIncluded(incKey.Key, source, std::move(header), true)) {
+ return false;
+ }
+ }
+ } else {
+ // Strict mode
+ for (IncludeKeyT const& incKey : parseData.Include.Dot) {
+ // Check if this is the sources own .moc file
+ bool const ownMoc = (incKey.Base == sourceBase);
+ if (!ownMoc) {
+ // Don't allow <BASE>.moc include other than own in regular mode
+ std::string msg = "The file includes the moc file ";
+ msg += Quoted(incKey.Key);
+ msg += ",\nwhich seems to be the moc file from a different "
+ "source file.\nThis is not supported. Include ";
+ msg += Quoted(sourceBase + ".moc");
+ msg += " to run moc on this source file.";
+ LogFileError(GenT::MOC, sourceFile.FileName, msg);
+ return false;
+ }
+ // Accept but issue a warning if moc isn't required
+ if (parseData.Macro.empty()) {
+ std::string msg = "The file includes the moc file ";
+ msg += Quoted(incKey.Key);
+ msg += ", but does not contain a ";
+ msg += MocConst().MacrosString();
+ msg += " macro.";
+ Log().WarningFile(GenT::MOC, sourceFile.FileName, msg);
+ }
+ // Create mapping
+ if (!MocRegisterIncluded(incKey.Key, source, source, false)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+cmQtAutoMocUic::SourceFileHandleT
+cmQtAutoMocUic::JobEvaluateT::MocFindIncludedHeader(
+ std::string const& includerDir, std::string const& includeBase) const
+{
+ // Search in vicinity of the source
+ {
+ SourceFileHandleT res = MocFindHeader(includerDir + includeBase);
+ if (res) {
+ return res;
+ }
+ }
+ // Search in include directories
+ for (std::string const& path : MocConst().IncludePaths) {
+ std::string testPath = path;
+ testPath += '/';
+ testPath += includeBase;
+ SourceFileHandleT res = MocFindHeader(testPath);
+ if (res) {
+ return res;
+ }
+ }
+ // Return without success
+ return SourceFileHandleT();
+}
+
+cmQtAutoMocUic::SourceFileHandleT cmQtAutoMocUic::JobEvaluateT::MocFindHeader(
+ std::string const& basePath) const
+{
+ std::string testPath;
+ testPath.reserve(basePath.size() + 8);
+ for (std::string const& ext : BaseConst().HeaderExtensions) {
+ testPath.clear();
+ testPath += basePath;
+ testPath += '.';
+ testPath += ext;
+ cmFileTime fileTime;
+ if (fileTime.Load(testPath)) {
+ // Compute real path of the file
+ testPath = cmSystemTools::GetRealPath(testPath);
+ // Return a known file if it exists already
+ {
+ auto it = BaseEval().Headers.find(testPath);
+ if (it != BaseEval().Headers.end()) {
+ return it->second;
+ }
+ }
+ // Created and return discovered file entry
+ SourceFileHandleT& res = MocEval().HeadersDiscovered[testPath];
+ if (!res) {
+ res = std::make_shared<SourceFileT>(testPath);
+ res->FileTime = fileTime;
+ res->Moc = true;
+ }
+ return res;
+ }
+ }
+ // Return without success
+ return SourceFileHandleT();
+}
+
+std::string cmQtAutoMocUic::JobEvaluateT::MocMessageTestHeaders(
+ std::string const& fileBase) const
+{
+ std::ostringstream res;
+ {
+ std::string exts = ".{";
+ exts += cmJoin(BaseConst().HeaderExtensions, ",");
+ exts += '}';
+ // Compose result string
+ res << " " << fileBase << exts << '\n';
+ for (std::string const& path : MocConst().IncludePaths) {
+ res << " " << path << '/' << fileBase << exts << '\n';
+ }
+ }
+ return res.str();
+}
+
+bool cmQtAutoMocUic::JobEvaluateT::MocRegisterIncluded(
+ std::string const& includeString, SourceFileHandleT includerFileHandle,
+ SourceFileHandleT sourceFileHandle, bool sourceIsHeader) const
+{
+ // Check if this file is already included
+ MappingHandleT& handle = MocEval().Includes[includeString];
+ if (handle) {
+ // Check if the output file would be generated from different source files
+ if (handle->SourceFile != sourceFileHandle) {
+ std::string msg = "The source files\n ";
+ msg += Quoted(includerFileHandle->FileName);
+ msg += '\n';
+ for (auto const& item : handle->IncluderFiles) {
+ msg += " ";
+ msg += Quoted(item->FileName);
+ msg += '\n';
+ }
+ msg += "contain the same include string ";
+ msg += Quoted(includeString);
+ msg += ", but\nthe moc file would be generated from different "
+ "source files\n ";
+ msg += Quoted(sourceFileHandle->FileName);
+ msg += " and\n ";
+ msg += Quoted(handle->SourceFile->FileName);
+ msg += ".\nConsider to\n"
+ " - not include the \"moc_<NAME>.cpp\" file\n"
+ " - add a directory prefix to a \"<NAME>.moc\" include "
+ "(e.g \"sub/<NAME>.moc\")\n"
+ " - rename the source file(s)\n";
+ LogError(GenT::MOC, msg);
+ return false;
+ }
+
+ // The same mapping already exists. Just add to the includers list.
+ handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
+ return true;
+ }
+
+ // Create a new mapping
+ handle = std::make_shared<MappingT>();
+ handle->IncludeString = includeString;
+ handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
+ handle->SourceFile = std::move(sourceFileHandle);
+ handle->OutputFile += Gen()->AbsoluteIncludePath(includeString);
+
+ // Register mapping in sources/headers map
+ MocRegisterMapping(handle, sourceIsHeader);
+ return true;
+}
+
+void cmQtAutoMocUic::JobEvaluateT::MocRegisterMapping(
+ MappingHandleT mappingHandle, bool sourceIsHeader) const
+{
+ auto& regMap =
+ sourceIsHeader ? MocEval().HeaderMappings : MocEval().SourceMappings;
+ // Check if source file already gets mapped
+ auto& regHandle = regMap[mappingHandle->SourceFile->FileName];
+ if (!regHandle) {
+ // Yet unknown mapping
+ regHandle = std::move(mappingHandle);
+ } else {
+ // Mappings with include string override those without
+ if (!mappingHandle->IncludeString.empty()) {
+ regHandle = std::move(mappingHandle);
+ }
+ }
+}
+
+bool cmQtAutoMocUic::JobEvaluateT::UicEval(SourceFileMapT const& fileMap)
+{
+ for (auto const& pair : fileMap) {
+ if (!UicEvalFile(pair.second)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoMocUic::JobEvaluateT::UicEvalFile(
+ SourceFileHandleT sourceFileHandle)
+{
+ SourceFileT const& sourceFile = *sourceFileHandle;
+ auto const& Include = sourceFile.ParseData->Uic.Include;
+ if (!sourceFile.Uic || Include.empty()) {
+ return true;
+ }
+
+ std::string const sourceDir = SubDirPrefix(sourceFile.FileName);
+ for (IncludeKeyT const& incKey : Include) {
+ // Find .ui file name
+ SourceFileHandleT uiFileHandle =
+ UicFindIncludedUi(sourceFile.FileName, sourceDir, incKey);
+ if (!uiFileHandle || UicConst().skipped(uiFileHandle->FileName)) {
+ continue;
+ }
+ // Register mapping
+ if (!UicRegisterMapping(incKey.Key, std::move(uiFileHandle),
+ std::move(sourceFileHandle))) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool cmQtAutoMocUic::JobEvaluateT::UicRegisterMapping(
+ std::string const& includeString, SourceFileHandleT uiFileHandle,
+ SourceFileHandleT includerFileHandle)
+{
+ auto& Includes = Gen()->UicEval().Includes;
+ auto it = Includes.find(includeString);
+ if (it != Includes.end()) {
+ MappingHandleT const& handle = it->second;
+ if (handle->SourceFile != uiFileHandle) {
+ // The output file already gets generated - from a different .ui file!
+ std::string msg = "The source files\n ";
+ msg += Quoted(includerFileHandle->FileName);
+ msg += '\n';
+ for (auto const& item : handle->IncluderFiles) {
+ msg += " ";
+ msg += Quoted(item->FileName);
+ msg += '\n';
+ }
+ msg += "contain the same include string ";
+ msg += Quoted(includeString);
+ msg += ", but\nthe uic file would be generated from different "
+ "user interface files\n ";
+ msg += Quoted(uiFileHandle->FileName);
+ msg += " and\n ";
+ msg += Quoted(handle->SourceFile->FileName);
+ msg += ".\nConsider to\n"
+ " - add a directory prefix to a \"ui_<NAME>.h\" include "
+ "(e.g \"sub/ui_<NAME>.h\")\n"
+ " - rename the <NAME>.ui file(s) and adjust the \"ui_<NAME>.h\" "
+ "include(s)\n";
+ LogError(GenT::UIC, msg);
+ return false;
+ }
+ // Add includer file to existing mapping
+ handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
+ } else {
+ // New mapping handle
+ MappingHandleT handle = std::make_shared<MappingT>();
+ handle->IncludeString = includeString;
+ handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
+ handle->SourceFile = std::move(uiFileHandle);
+ handle->OutputFile += Gen()->AbsoluteIncludePath(includeString);
+ // Register mapping
+ Includes.emplace(includeString, std::move(handle));
+ }
+ return true;
+}
+
+cmQtAutoMocUic::SourceFileHandleT
+cmQtAutoMocUic::JobEvaluateT::UicFindIncludedUi(
+ std::string const& sourceFile, std::string const& sourceDir,
+ IncludeKeyT const& incKey) const
+{
+ std::string searchFileName = incKey.Base;
+ searchFileName += ".ui";
+ // Collect search paths list
+ std::vector<std::string> testFiles;
+ {
+ auto& searchPaths = UicConst().SearchPaths;
+ testFiles.reserve((searchPaths.size() + 1) * 2);
+
+ // Vicinity of the source
+ testFiles.emplace_back(sourceDir + searchFileName);
+ if (!incKey.Dir.empty()) {
+ std::string path = sourceDir;
+ path += incKey.Dir;
+ path += searchFileName;
+ testFiles.emplace_back(path);
+ }
+ // AUTOUIC search paths
+ if (!searchPaths.empty()) {
+ for (std::string const& sPath : searchPaths) {
+ std::string path = sPath;
+ path += '/';
+ path += searchFileName;
+ testFiles.emplace_back(std::move(path));
+ }
+ if (!incKey.Dir.empty()) {
+ for (std::string const& sPath : searchPaths) {
+ std::string path = sPath;
+ path += '/';
+ path += incKey.Dir;
+ path += searchFileName;
+ testFiles.emplace_back(std::move(path));
+ }
+ }
+ }
+ }
+
+ // Search for the .ui file!
+ for (std::string const& testFile : testFiles) {
+ cmFileTime fileTime;
+ if (fileTime.Load(testFile)) {
+ // .ui file found in files system!
+ std::string realPath = cmSystemTools::GetRealPath(testFile);
+ // Get or create .ui file handle
+ SourceFileHandleT& handle = Gen()->UicEval().UiFiles[realPath];
+ if (!handle) {
+ // The file wasn't registered, yet
+ handle = std::make_shared<SourceFileT>(realPath);
+ handle->FileTime = fileTime;
+ }
+ return handle;
+ }
+ }
+
+ // Log error
+ {
+ std::string msg = "The file includes the uic file ";
+ msg += Quoted(incKey.Key);
+ msg += ",\nbut the user interface file ";
+ msg += Quoted(searchFileName);
+ msg += "\ncould not be found in the following locations\n";
+ for (std::string const& testFile : testFiles) {
+ msg += " ";
+ msg += Quoted(testFile);
+ msg += '\n';
+ }
+ LogFileError(GenT::UIC, sourceFile, msg);
+ }
+
+ return SourceFileHandleT();
+}
+
+void cmQtAutoMocUic::JobGenerateT::Process()
+{
+ // Add moc compile jobs
+ if (MocConst().Enabled) {
+ for (auto const& pair : MocEval().HeaderMappings) {
+ // Register if this mapping is a candidate for mocs_compilation.cpp
+ bool const compFile = pair.second->IncludeString.empty();
+ if (compFile) {
+ MocEval().CompFiles.emplace_back(pair.second->SourceFile->BuildPath);
+ }
+ if (!MocGenerate(pair.second, compFile)) {
+ return;
+ }
+ }
+ for (auto const& pair : MocEval().SourceMappings) {
+ if (!MocGenerate(pair.second, false)) {
+ return;
+ }
+ }
+
+ // Add mocs compilations job on demand
+ Gen()->WorkerPool().EmplaceJob<JobMocsCompilationT>();
+ }
+
+ // Add uic compile jobs
+ if (UicConst().Enabled) {
+ for (auto const& pair : Gen()->UicEval().Includes) {
+ if (!UicGenerate(pair.second)) {
+ return;
+ }
+ }
+ }
+
+ // Add finish job
+ Gen()->WorkerPool().EmplaceJob<JobFinishT>();
+}
+
+bool cmQtAutoMocUic::JobGenerateT::MocGenerate(MappingHandleT const& mapping,
+ bool compFile) const
+{
+ std::unique_ptr<std::string> reason;
+ if (Log().Verbose()) {
+ reason = cm::make_unique<std::string>();
+ }
+ if (MocUpdate(*mapping, reason.get())) {
+ // Create the parent directory
+ if (!MakeParentDirectory(mapping->OutputFile)) {
+ LogFileError(GenT::MOC, mapping->OutputFile,
+ "Could not create parent directory.");
+ return false;
+ }
+ // Add moc job
+ Gen()->WorkerPool().EmplaceJob<JobMocT>(mapping, std::move(reason));
+ // Check if a moc job for a mocs_compilation.cpp entry was generated
+ if (compFile) {
+ MocEval().CompUpdated = true;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoMocUic::JobGenerateT::MocUpdate(MappingT const& mapping,
+ std::string* reason) const
+{
+ std::string const& sourceFile = mapping.SourceFile->FileName;
+ std::string const& outputFile = mapping.OutputFile;
+
+ // Test if the output file exists
+ cmFileTime outputFileTime;
+ if (!outputFileTime.Load(outputFile)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because it doesn't exist, from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ // Test if any setting changed
+ if (MocConst().SettingsChanged) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because the uic settings changed, from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ // Test if the source file is newer
+ if (outputFileTime.Older(mapping.SourceFile->FileTime)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because it's older than its source file, from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ // Test if the moc_predefs file is newer
+ if (!MocConst().PredefsFileAbs.empty()) {
+ if (outputFileTime.Older(MocEval().PredefsTime)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because it's older than ";
+ *reason += Quoted(MocConst().PredefsFileAbs);
+ *reason += ", from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+ }
+
+ // Test if the moc executable is newer
+ if (outputFileTime.Older(MocConst().ExecutableTime)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because it's older than the moc executable, from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ // Test if a dependency file is newer
+ {
+ // Check dependency timestamps
+ std::string const sourceDir = SubDirPrefix(sourceFile);
+ for (std::string const& dep : mapping.SourceFile->ParseData->Moc.Depends) {
+ // Find dependency file
+ auto const depMatch = MocFindDependency(sourceDir, dep);
+ if (depMatch.first.empty()) {
+ Log().WarningFile(GenT::MOC, sourceFile,
+ "Could not find dependency file " + Quoted(dep));
+ continue;
+ }
+ // Test if dependency file is older
+ if (outputFileTime.Older(depMatch.second)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because it's older than its dependency file ";
+ *reason += Quoted(depMatch.first);
+ *reason += ", from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+std::pair<std::string, cmFileTime>
+cmQtAutoMocUic::JobGenerateT::MocFindDependency(
+ std::string const& sourceDir, std::string const& includeString) const
+{
+ typedef std::pair<std::string, cmFileTime> ResPair;
+ // Search in vicinity of the source
+ {
+ ResPair res{ sourceDir + includeString, {} };
+ if (res.second.Load(res.first)) {
+ return res;
+ }
+ }
+ // Search in include directories
+ for (std::string const& includePath : MocConst().IncludePaths) {
+ ResPair res{ includePath, {} };
+ res.first += '/';
+ res.first += includeString;
+ if (res.second.Load(res.first)) {
+ return res;
+ }
+ }
+ // Return empty
+ return ResPair();
+}
+
+bool cmQtAutoMocUic::JobGenerateT::UicGenerate(
+ MappingHandleT const& mapping) const
+{
+ std::unique_ptr<std::string> reason;
+ if (Log().Verbose()) {
+ reason = cm::make_unique<std::string>();
+ }
+ if (UicUpdate(*mapping, reason.get())) {
+ // Create the parent directory
+ if (!MakeParentDirectory(mapping->OutputFile)) {
+ LogFileError(GenT::UIC, mapping->OutputFile,
+ "Could not create parent directory.");
+ return false;
+ }
+ // Add uic job
+ Gen()->WorkerPool().EmplaceJob<JobUicT>(mapping, std::move(reason));
+ }
+ return true;
+}
+
+bool cmQtAutoMocUic::JobGenerateT::UicUpdate(MappingT const& mapping,
+ std::string* reason) const
+{
+ std::string const& sourceFile = mapping.SourceFile->FileName;
+ std::string const& outputFile = mapping.OutputFile;
+
+ // Test if the build file exists
+ cmFileTime outputFileTime;
+ if (!outputFileTime.Load(outputFile)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because it doesn't exist, from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ // Test if the uic settings changed
+ if (UicConst().SettingsChanged) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because the uic settings changed, from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ // Test if the source file is newer
+ if (outputFileTime.Older(mapping.SourceFile->FileTime)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += " because it's older than the source file ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ // Test if the uic executable is newer
+ if (outputFileTime.Older(UicConst().ExecutableTime)) {
+ if (reason != nullptr) {
+ *reason = "Generating ";
+ *reason += Quoted(outputFile);
+ *reason += ", because it's older than the uic executable, from ";
+ *reason += Quoted(sourceFile);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void cmQtAutoMocUic::JobMocT::Process()
+{
+ std::string const& sourceFile = Mapping->SourceFile->FileName;
+ std::string const& outputFile = Mapping->OutputFile;
+
+ // Compose moc command
+ std::vector<std::string> cmd;
+ cmd.push_back(MocConst().Executable);
+ // Add options
+ cmAppend(cmd, MocConst().AllOptions);
+ // Add predefs include
+ if (!MocConst().PredefsFileAbs.empty()) {
+ cmd.emplace_back("--include");
+ cmd.push_back(MocConst().PredefsFileAbs);
+ }
+ cmd.emplace_back("-o");
+ cmd.push_back(outputFile);
+ cmd.push_back(sourceFile);
+
+ // Execute moc command
+ cmWorkerPool::ProcessResultT result;
+ if (RunProcess(GenT::MOC, result, cmd, Reason.get())) {
+ // Moc command success. Print moc output.
+ if (!result.StdOut.empty()) {
+ Log().Info(GenT::MOC, result.StdOut);
+ }
+ } else {
+ // Moc command failed
+ std::string msg = "The moc process failed to compile\n ";
+ msg += Quoted(sourceFile);
+ msg += "\ninto\n ";
+ msg += Quoted(outputFile);
+ if (Mapping->IncluderFiles.empty()) {
+ msg += ".\n";
+ } else {
+ msg += "\nincluded by\n";
+ for (auto const& item : Mapping->IncluderFiles) {
+ msg += " ";
+ msg += Quoted(item->FileName);
+ msg += '\n';
+ }
+ }
+ msg += result.ErrorMessage;
+ LogCommandError(GenT::MOC, msg, cmd, result.StdOut);
+ }
+}
+
+void cmQtAutoMocUic::JobUicT::Process()
+{
+ std::string const& sourceFile = Mapping->SourceFile->FileName;
+ std::string const& outputFile = Mapping->OutputFile;
+
+ // Compose uic command
+ std::vector<std::string> cmd;
+ cmd.push_back(UicConst().Executable);
+ {
+ std::vector<std::string> allOpts = UicConst().TargetOptions;
+ auto optionIt = UicConst().Options.find(sourceFile);
+ if (optionIt != UicConst().Options.end()) {
+ UicMergeOptions(allOpts, optionIt->second,
+ (BaseConst().QtVersionMajor == 5));
+ }
+ cmAppend(cmd, allOpts);
+ }
+ cmd.emplace_back("-o");
+ cmd.emplace_back(outputFile);
+ cmd.emplace_back(sourceFile);
+
+ cmWorkerPool::ProcessResultT result;
+ if (RunProcess(GenT::UIC, result, cmd, Reason.get())) {
+ // Uic command success
+ // Print uic output
+ if (!result.StdOut.empty()) {
+ Log().Info(GenT::UIC, result.StdOut);
+ }
+ } else {
+ // Uic command failed
+ std::string msg = "The uic process failed to compile\n ";
+ msg += Quoted(sourceFile);
+ msg += "\ninto\n ";
+ msg += Quoted(outputFile);
+ msg += "\nincluded by\n";
+ for (auto const& item : Mapping->IncluderFiles) {
+ msg += " ";
+ msg += Quoted(item->FileName);
+ msg += '\n';
+ }
+ msg += result.ErrorMessage;
+ LogCommandError(GenT::UIC, msg, cmd, result.StdOut);
+ }
+}
+
+void cmQtAutoMocUic::JobMocsCompilationT::Process()
+{
+ // Compose mocs compilation file content
+ std::string content =
+ "// This file is autogenerated. Changes will be overwritten.\n";
+
+ if (MocEval().CompFiles.empty()) {
+ // Placeholder content
+ content += "// No files found that require moc or the moc files are "
+ "included\n";
+ content += "enum some_compilers { need_more_than_nothing };\n";
+ } else {
+ // Valid content
+ char const clampB = BaseConst().MultiConfig ? '<' : '"';
+ char const clampE = BaseConst().MultiConfig ? '>' : '"';
+ for (std::string const& mocfile : MocEval().CompFiles) {
+ content += "#include ";
+ content += clampB;
+ content += mocfile;
+ content += clampE;
+ content += '\n';
+ }
+ }
+
+ std::string const& compAbs = MocConst().CompFileAbs;
+ if (cmQtAutoGenerator::FileDiffers(compAbs, content)) {
+ // Actually write mocs compilation file
+ if (Log().Verbose()) {
+ Log().Info(GenT::MOC, "Generating MOC compilation " + compAbs);
+ }
+ if (!FileWrite(compAbs, content)) {
+ LogFileError(GenT::MOC, compAbs,
+ "mocs compilation file writing failed.");
+ }
+ } else if (MocEval().CompUpdated) {
+ // Only touch mocs compilation file
+ if (Log().Verbose()) {
+ Log().Info(GenT::MOC, "Touching mocs compilation " + compAbs);
+ }
+ if (!cmSystemTools::Touch(compAbs, false)) {
+ LogFileError(GenT::MOC, compAbs,
+ "mocs compilation file touching failed.");
+ }
+ }
+}
+
+void cmQtAutoMocUic::JobFinishT::Process()
+{
+ Gen()->AbortSuccess();
+}
+
+cmQtAutoMocUic::cmQtAutoMocUic() = default;
+cmQtAutoMocUic::~cmQtAutoMocUic() = default;
+
+bool cmQtAutoMocUic::Init(cmMakefile* makefile)
+{
+ // Utility lambdas
+ auto InfoGet = [makefile](const char* key) {
+ return makefile->GetSafeDefinition(key);
+ };
+ auto InfoGetBool = [makefile](const char* key) {
+ return makefile->IsOn(key);
+ };
+ auto InfoGetList = [makefile](const char* key) -> std::vector<std::string> {
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list);
+ return list;
+ };
+ auto InfoGetLists =
+ [makefile](const char* key) -> std::vector<std::vector<std::string>> {
+ std::vector<std::vector<std::string>> lists;
+ {
+ std::string const value = makefile->GetSafeDefinition(key);
+ std::string::size_type pos = 0;
+ while (pos < value.size()) {
+ std::string::size_type next = value.find(ListSep, pos);
+ std::string::size_type length =
+ (next != std::string::npos) ? next - pos : value.size() - pos;
+ // Remove enclosing braces
+ if (length >= 2) {
+ std::string::const_iterator itBeg = value.begin() + (pos + 1);
+ std::string::const_iterator itEnd = itBeg + (length - 2);
+ {
+ std::string subValue(itBeg, itEnd);
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(subValue, list);
+ lists.push_back(std::move(list));
+ }
+ }
+ pos += length;
+ pos += ListSep.size();
+ }
+ }
+ return lists;
+ };
+ auto InfoGetConfig = [makefile, this](const char* key) -> std::string {
+ const char* valueConf = nullptr;
+ {
+ std::string keyConf = key;
+ keyConf += '_';
+ keyConf += InfoConfig();
+ valueConf = makefile->GetDefinition(keyConf);
+ }
+ if (valueConf == nullptr) {
+ return makefile->GetSafeDefinition(key);
+ }
+ return std::string(valueConf);
+ };
+ auto InfoGetConfigList =
+ [&InfoGetConfig](const char* key) -> std::vector<std::string> {
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
+ return list;
+ };
+ auto LogInfoError = [this](std::string const& msg) -> bool {
+ std::ostringstream err;
+ err << "In " << Quoted(this->InfoFile()) << ":\n" << msg;
+ this->Log().Error(GenT::GEN, err.str());
+ return false;
+ };
+ auto MatchSizes = [&LogInfoError](const char* keyA, const char* keyB,
+ std::size_t sizeA,
+ std::size_t sizeB) -> bool {
+ if (sizeA == sizeB) {
+ return true;
+ }
+ std::ostringstream err;
+ err << "Lists sizes mismatch " << keyA << '(' << sizeA << ") " << keyB
+ << '(' << sizeB << ')';
+ return LogInfoError(err.str());
+ };
+
+ // -- Read info file
+ if (!makefile->ReadListFile(InfoFile())) {
+ return LogInfoError("File processing failed");
+ }
+
+ // -- Meta
+ Logger_.RaiseVerbosity(InfoGet("AM_VERBOSITY"));
+ BaseConst_.MultiConfig = InfoGetBool("AM_MULTI_CONFIG");
+ {
+ unsigned long num = 1;
+ if (cmSystemTools::StringToULong(InfoGet("AM_PARALLEL").c_str(), &num)) {
+ num = std::max<unsigned long>(num, 1);
+ num = std::min<unsigned long>(num, ParallelMax);
+ }
+ WorkerPool_.SetThreadCount(static_cast<unsigned int>(num));
+ }
+ BaseConst_.HeaderExtensions =
+ makefile->GetCMakeInstance()->GetHeaderExtensions();
+
+ // - Files and directories
+ BaseConst_.IncludeProjectDirsBefore =
+ InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
+ BaseConst_.ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR");
+ BaseConst_.ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR");
+ BaseConst_.CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR");
+ BaseConst_.CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR");
+ BaseConst_.AutogenBuildDir = InfoGet("AM_BUILD_DIR");
+ if (BaseConst_.AutogenBuildDir.empty()) {
+ return LogInfoError("Autogen build directory missing.");
+ }
+ BaseConst_.AutogenIncludeDir = InfoGetConfig("AM_INCLUDE_DIR");
+ if (BaseConst_.AutogenIncludeDir.empty()) {
+ return LogInfoError("Autogen include directory missing.");
+ }
+ BaseConst_.CMakeExecutable = InfoGetConfig("AM_CMAKE_EXECUTABLE");
+ if (BaseConst_.CMakeExecutable.empty()) {
+ return LogInfoError("CMake executable file name missing.");
+ }
+ if (!BaseConst_.CMakeExecutableTime.Load(BaseConst_.CMakeExecutable)) {
+ std::string error = "The CMake executable ";
+ error += Quoted(BaseConst_.CMakeExecutable);
+ error += " does not exist.";
+ return LogInfoError(error);
+ }
+ BaseConst_.ParseCacheFile = InfoGetConfig("AM_PARSE_CACHE_FILE");
+ if (BaseConst_.ParseCacheFile.empty()) {
+ return LogInfoError("Parse cache file name missing.");
+ }
+
+ // - Settings file
+ SettingsFile_ = InfoGetConfig("AM_SETTINGS_FILE");
+ if (SettingsFile_.empty()) {
+ return LogInfoError("Settings file name missing.");
+ }
+
+ // - Qt environment
+ {
+ unsigned long qtv = BaseConst_.QtVersionMajor;
+ if (cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR").c_str(),
+ &qtv)) {
+ BaseConst_.QtVersionMajor = static_cast<unsigned int>(qtv);
+ }
+ }
+
+ // - Moc
+ MocConst_.Executable = InfoGet("AM_QT_MOC_EXECUTABLE");
+ if (!MocConst().Executable.empty()) {
+ MocConst_.Enabled = true;
+ // Load the executable file time
+ if (!MocConst_.ExecutableTime.Load(MocConst_.Executable)) {
+ std::string error = "The moc executable ";
+ error += Quoted(MocConst_.Executable);
+ error += " does not exist.";
+ return LogInfoError(error);
+ }
+ for (std::string& sfl : InfoGetList("AM_MOC_SKIP")) {
+ MocConst_.SkipList.insert(std::move(sfl));
+ }
+ MocConst_.Definitions = InfoGetConfigList("AM_MOC_DEFINITIONS");
+ MocConst_.IncludePaths = InfoGetConfigList("AM_MOC_INCLUDES");
+ MocConst_.Options = InfoGetList("AM_MOC_OPTIONS");
+ MocConst_.RelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE");
+ for (std::string const& item : InfoGetList("AM_MOC_MACRO_NAMES")) {
+ MocConst_.MacroFilters.emplace_back(
+ item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
+ }
+ {
+ auto addFilter = [this, &LogInfoError](std::string const& key,
+ std::string const& exp) -> bool {
+ auto filterErr = [&LogInfoError, &key, &exp](const char* err) -> bool {
+ std::ostringstream ferr;
+ ferr << "AUTOMOC_DEPEND_FILTERS: " << err << '\n';
+ ferr << " Key: " << Quoted(key) << '\n';
+ ferr << " Exp: " << Quoted(exp) << '\n';
+ return LogInfoError(ferr.str());
+ };
+ if (key.empty()) {
+ return filterErr("Key is empty");
+ }
+ if (exp.empty()) {
+ return filterErr("Regular expression is empty");
+ }
+ this->MocConst_.DependFilters.emplace_back(key, exp);
+ if (!this->MocConst_.DependFilters.back().Exp.is_valid()) {
+ return filterErr("Regular expression compiling failed");
+ }
+ return true;
+ };
+
+ // Insert default filter for Q_PLUGIN_METADATA
+ if (BaseConst().QtVersionMajor != 4) {
+ if (!addFilter("Q_PLUGIN_METADATA",
+ "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
+ "[^\\)]*FILE[ \t]*\"([^\"]+)\"")) {
+ return false;
+ }
+ }
+ // Insert user defined dependency filters
+ std::vector<std::string> flts = InfoGetList("AM_MOC_DEPEND_FILTERS");
+ if ((flts.size() % 2) != 0) {
+ return LogInfoError(
+ "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2");
+ }
+ for (auto itC = flts.begin(), itE = flts.end(); itC != itE; itC += 2) {
+ if (!addFilter(*itC, *(itC + 1))) {
+ return false;
+ }
+ }
+ }
+ MocConst_.PredefsCmd = InfoGetList("AM_MOC_PREDEFS_CMD");
+ }
+
+ // - Uic
+ UicConst_.Executable = InfoGet("AM_QT_UIC_EXECUTABLE");
+ if (!UicConst().Executable.empty()) {
+ UicConst_.Enabled = true;
+ // Load the executable file time
+ if (!UicConst_.ExecutableTime.Load(UicConst_.Executable)) {
+ std::string error = "The uic executable ";
+ error += Quoted(UicConst_.Executable);
+ error += " does not exist.";
+ return LogInfoError(error);
+ }
+ for (std::string& sfl : InfoGetList("AM_UIC_SKIP")) {
+ UicConst_.SkipList.insert(std::move(sfl));
+ }
+ UicConst_.SearchPaths = InfoGetList("AM_UIC_SEARCH_PATHS");
+ UicConst_.TargetOptions = InfoGetConfigList("AM_UIC_TARGET_OPTIONS");
+ {
+ const char* keyFiles = "AM_UIC_OPTIONS_FILES";
+ const char* keyOpts = "AM_UIC_OPTIONS_OPTIONS";
+ auto sources = InfoGetList(keyFiles);
+ auto options = InfoGetLists(keyOpts);
+ if (!MatchSizes(keyFiles, keyOpts, sources.size(), options.size())) {
+ return false;
+ }
+ auto fitEnd = sources.cend();
+ auto fit = sources.begin();
+ auto oit = options.begin();
+ while (fit != fitEnd) {
+ UicConst_.Options[*fit] = std::move(*oit);
+ ++fit;
+ ++oit;
+ }
+ }
+ }
+
+ // - Headers and sources
+ {
+ auto makeSource =
+ [&LogInfoError](std::string const& fileName,
+ std::string const& fileFlags) -> SourceFileHandleT {
+ if (fileFlags.size() != 2) {
+ LogInfoError("Invalid file flags string size");
+ return SourceFileHandleT();
+ }
+ cmFileTime fileTime;
+ if (!fileTime.Load(fileName)) {
+ LogInfoError("The source file " + cmQtAutoGen::Quoted(fileName) +
+ " does not exist.");
+ return SourceFileHandleT();
+ }
+ SourceFileHandleT sfh = std::make_shared<SourceFileT>(fileName);
+ sfh->FileTime = fileTime;
+ sfh->Moc = (fileFlags[0] == 'M');
+ sfh->Uic = (fileFlags[1] == 'U');
+ return sfh;
+ };
+
+ // Headers
+ {
+ // Get file lists
+ const char *keyFiles = "AM_HEADERS", *keyFlags = "AM_HEADERS_FLAGS";
+ std::vector<std::string> files = InfoGetList(keyFiles);
+ std::vector<std::string> flags = InfoGetList(keyFlags);
+ std::vector<std::string> builds;
+ if (!MatchSizes(keyFiles, keyFlags, files.size(), flags.size())) {
+ return false;
+ }
+ if (MocConst().Enabled) {
+ const char* keyPaths = "AM_HEADERS_BUILD_PATHS";
+ builds = InfoGetList(keyPaths);
+ if (!MatchSizes(keyFiles, keyPaths, files.size(), builds.size())) {
+ return false;
+ }
+ }
+ // Process file lists
+ for (std::size_t ii = 0; ii != files.size(); ++ii) {
+ std::string& fileName(files[ii]);
+ SourceFileHandleT sfh = makeSource(fileName, flags[ii]);
+ if (!sfh) {
+ return false;
+ }
+ if (MocConst().Enabled) {
+ sfh->BuildPath = std::move(builds[ii]);
+ if (sfh->BuildPath.empty()) {
+ Log().ErrorFile(GenT::GEN, this->InfoFile(),
+ "Header file build path is empty");
+ return false;
+ }
+ }
+ BaseEval().Headers.emplace(std::move(fileName), std::move(sfh));
+ }
+ }
+
+ // Sources
+ {
+ const char *keyFiles = "AM_SOURCES", *keyFlags = "AM_SOURCES_FLAGS";
+ std::vector<std::string> files = InfoGetList(keyFiles);
+ std::vector<std::string> flags = InfoGetList(keyFlags);
+ if (!MatchSizes(keyFiles, keyFlags, files.size(), flags.size())) {
+ return false;
+ }
+ // Process file lists
+ for (std::size_t ii = 0; ii != files.size(); ++ii) {
+ std::string& fileName(files[ii]);
+ SourceFileHandleT sfh = makeSource(fileName, flags[ii]);
+ if (!sfh) {
+ return false;
+ }
+ BaseEval().Sources.emplace(std::move(fileName), std::move(sfh));
+ }
+ }
+ }
+
+ // Init derived information
+ // ------------------------
+
+ // Moc variables
+ if (MocConst().Enabled) {
+ // Mocs compilation file
+ MocConst_.CompFileAbs = AbsoluteBuildPath("mocs_compilation.cpp");
+
+ // Moc predefs file
+ if (!MocConst_.PredefsCmd.empty()) {
+ MocConst_.PredefsFileRel = "moc_predefs";
+ if (BaseConst_.MultiConfig) {
+ MocConst_.PredefsFileRel += '_';
+ MocConst_.PredefsFileRel += InfoConfig();
+ }
+ MocConst_.PredefsFileRel += ".h";
+ MocConst_.PredefsFileAbs = AbsoluteBuildPath(MocConst().PredefsFileRel);
+ }
+
+ // Sort include directories on demand
+ if (BaseConst().IncludeProjectDirsBefore) {
+ // Move strings to temporary list
+ std::list<std::string> includes(MocConst().IncludePaths.begin(),
+ MocConst().IncludePaths.end());
+ MocConst_.IncludePaths.clear();
+ MocConst_.IncludePaths.reserve(includes.size());
+ // Append project directories only
+ {
+ std::array<std::string const*, 2> const movePaths = {
+ { &BaseConst().ProjectBinaryDir, &BaseConst().ProjectSourceDir }
+ };
+ for (std::string const* ppath : movePaths) {
+ std::list<std::string>::iterator it = includes.begin();
+ while (it != includes.end()) {
+ std::string const& path = *it;
+ if (cmSystemTools::StringStartsWith(path, ppath->c_str())) {
+ MocConst_.IncludePaths.push_back(path);
+ it = includes.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+ }
+ // Append remaining directories
+ MocConst_.IncludePaths.insert(MocConst_.IncludePaths.end(),
+ includes.begin(), includes.end());
+ }
+ // Compose moc includes list
+ {
+ std::set<std::string> frameworkPaths;
+ for (std::string const& path : MocConst().IncludePaths) {
+ MocConst_.Includes.push_back("-I" + path);
+ // Extract framework path
+ if (cmHasLiteralSuffix(path, ".framework/Headers")) {
+ // Go up twice to get to the framework root
+ std::vector<std::string> pathComponents;
+ cmSystemTools::SplitPath(path, pathComponents);
+ frameworkPaths.emplace(cmSystemTools::JoinPath(
+ pathComponents.begin(), pathComponents.end() - 2));
+ }
+ }
+ // Append framework includes
+ for (std::string const& path : frameworkPaths) {
+ MocConst_.Includes.emplace_back("-F");
+ MocConst_.Includes.push_back(path);
+ }
+ }
+ // Setup single list with all options
+ {
+ // Add includes
+ MocConst_.AllOptions.insert(MocConst_.AllOptions.end(),
+ MocConst().Includes.begin(),
+ MocConst().Includes.end());
+ // Add definitions
+ for (std::string const& def : MocConst().Definitions) {
+ MocConst_.AllOptions.push_back("-D" + def);
+ }
+ // Add options
+ MocConst_.AllOptions.insert(MocConst_.AllOptions.end(),
+ MocConst().Options.begin(),
+ MocConst().Options.end());
+ }
+ }
+
+ return true;
+}
+
+template <class JOBTYPE>
+void cmQtAutoMocUic::CreateParseJobs(SourceFileMapT const& sourceMap)
+{
+ cmFileTime const parseCacheTime = BaseEval().ParseCacheTime;
+ ParseCacheT& parseCache = BaseEval().ParseCache;
+ for (auto& src : sourceMap) {
+ // Get or create the file parse data reference
+ ParseCacheT::GetOrInsertT cacheEntry = parseCache.GetOrInsert(src.first);
+ src.second->ParseData = std::move(cacheEntry.first);
+ // Create a parse job if the cache file was missing or is older
+ if (cacheEntry.second || src.second->FileTime.Newer(parseCacheTime)) {
+ BaseEval().ParseCacheChanged = true;
+ WorkerPool().EmplaceJob<JOBTYPE>(src.second);
+ }
+ }
+}
+
+void cmQtAutoMocUic::InitJobs()
+{
+ // Add moc_predefs.h job
+ if (MocConst().Enabled && !MocConst().PredefsCmd.empty()) {
+ WorkerPool().EmplaceJob<JobMocPredefsT>();
+ }
+ // Add header parse jobs
+ CreateParseJobs<JobParseHeaderT>(BaseEval().Headers);
+ // Add source parse jobs
+ CreateParseJobs<JobParseSourceT>(BaseEval().Sources);
+ // Add evaluate job
+ WorkerPool().EmplaceJob<JobEvaluateT>();
+}
+
+bool cmQtAutoMocUic::Process()
+{
+ SettingsFileRead();
+ ParseCacheRead();
+ if (!CreateDirectories()) {
+ return false;
+ }
+ InitJobs();
+ if (!WorkerPool_.Process(this)) {
+ return false;
+ }
+ if (JobError_) {
+ return false;
+ }
+ if (!ParseCacheWrite()) {
+ return false;
+ }
+ if (!SettingsFileWrite()) {
+ return false;
+ }
+ return true;
+}
+
+void cmQtAutoMocUic::SettingsFileRead()
+{
+ // Compose current settings strings
+ {
+ cmCryptoHash cryptoHash(cmCryptoHash::AlgoSHA256);
+ std::string const sep(";");
+ auto cha = [&cryptoHash, &sep](std::string const& value) {
+ cryptoHash.Append(value);
+ cryptoHash.Append(sep);
+ };
+
+ if (MocConst_.Enabled) {
+ cryptoHash.Initialize();
+ cha(MocConst().Executable);
+ for (auto const& value : MocConst().AllOptions) {
+ cha(value);
+ }
+ cha(BaseConst().IncludeProjectDirsBefore ? "TRUE" : "FALSE");
+ for (auto const& value : MocConst().PredefsCmd) {
+ cha(value);
+ }
+ for (auto const& filter : MocConst().DependFilters) {
+ cha(filter.Key);
+ }
+ for (auto const& filter : MocConst().MacroFilters) {
+ cha(filter.Key);
+ }
+ SettingsStringMoc_ = cryptoHash.FinalizeHex();
+ }
+
+ if (UicConst().Enabled) {
+ cryptoHash.Initialize();
+ cha(UicConst().Executable);
+ for (auto const& value : UicConst().TargetOptions) {
+ cha(value);
+ }
+ for (const auto& item : UicConst().Options) {
+ cha(item.first);
+ for (auto const& svalue : item.second) {
+ cha(svalue);
+ }
+ }
+ SettingsStringUic_ = cryptoHash.FinalizeHex();
+ }
+ }
+
+ // Read old settings and compare
+ {
+ std::string content;
+ if (cmQtAutoGenerator::FileRead(content, SettingsFile_)) {
+ if (MocConst().Enabled) {
+ if (SettingsStringMoc_ != SettingsFind(content, "moc")) {
+ MocConst_.SettingsChanged = true;
+ }
+ }
+ if (UicConst().Enabled) {
+ if (SettingsStringUic_ != SettingsFind(content, "uic")) {
+ UicConst_.SettingsChanged = true;
+ }
+ }
+ // In case any setting changed remove the old settings file.
+ // This triggers a full rebuild on the next run if the current
+ // build is aborted before writing the current settings in the end.
+ if (MocConst().SettingsChanged || UicConst().SettingsChanged) {
+ cmSystemTools::RemoveFile(SettingsFile_);
+ }
+ } else {
+ // Settings file read failed
+ if (MocConst().Enabled) {
+ MocConst_.SettingsChanged = true;
+ }
+ if (UicConst().Enabled) {
+ UicConst_.SettingsChanged = true;
+ }
+ }
+ }
+}
+
+bool cmQtAutoMocUic::SettingsFileWrite()
+{
+ // Only write if any setting changed
+ if (MocConst().SettingsChanged || UicConst().SettingsChanged) {
+ if (Log().Verbose()) {
+ Log().Info(GenT::GEN, "Writing settings file " + Quoted(SettingsFile_));
+ }
+ // Compose settings file content
+ std::string content;
+ {
+ auto SettingAppend = [&content](const char* key,
+ std::string const& value) {
+ if (!value.empty()) {
+ content += key;
+ content += ':';
+ content += value;
+ content += '\n';
+ }
+ };
+ SettingAppend("moc", SettingsStringMoc_);
+ SettingAppend("uic", SettingsStringUic_);
+ }
+ // Write settings file
+ std::string error;
+ if (!cmQtAutoGenerator::FileWrite(SettingsFile_, content, &error)) {
+ Log().ErrorFile(GenT::GEN, SettingsFile_,
+ "Settings file writing failed. " + error);
+ // Remove old settings file to trigger a full rebuild on the next run
+ cmSystemTools::RemoveFile(SettingsFile_);
+ return false;
+ }
+ }
+ return true;
+}
+
+void cmQtAutoMocUic::ParseCacheRead()
+{
+ const char* reason = nullptr;
+ // Don't read the cache if it is invalid
+ if (!BaseEval().ParseCacheTime.Load(BaseConst().ParseCacheFile)) {
+ reason = "Refreshing parse cache because it doesn't exist.";
+ } else if (MocConst().SettingsChanged || UicConst().SettingsChanged) {
+ reason = "Refreshing parse cache because the settings changed.";
+ } else if (BaseEval().ParseCacheTime.Older(
+ BaseConst().CMakeExecutableTime)) {
+ reason =
+ "Refreshing parse cache because it is older than the CMake executable.";
+ }
+
+ if (reason != nullptr) {
+ // Don't read but refresh the complete parse cache
+ if (Log().Verbose()) {
+ Log().Info(GenT::GEN, reason);
+ }
+ BaseEval().ParseCacheChanged = true;
+ } else {
+ // Read parse cache
+ BaseEval().ParseCache.ReadFromFile(BaseConst().ParseCacheFile);
+ }
+}
+
+bool cmQtAutoMocUic::ParseCacheWrite()
+{
+ if (BaseEval().ParseCacheChanged) {
+ if (Log().Verbose()) {
+ Log().Info(GenT::GEN,
+ "Writing parse cache file " +
+ Quoted(BaseConst().ParseCacheFile));
+ }
+ if (!BaseEval().ParseCache.WriteToFile(BaseConst().ParseCacheFile)) {
+ Log().ErrorFile(GenT::GEN, BaseConst().ParseCacheFile,
+ "Parse cache file writing failed.");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoMocUic::CreateDirectories()
+{
+ // Create AUTOGEN include directory
+ if (!cmSystemTools::MakeDirectory(BaseConst().AutogenIncludeDir)) {
+ Log().ErrorFile(GenT::GEN, BaseConst().AutogenIncludeDir,
+ "Could not create directory.");
+ return false;
+ }
+ return true;
+}
+
+void cmQtAutoMocUic::Abort(bool error)
+{
+ if (error) {
+ JobError_.store(true);
+ }
+ WorkerPool_.Abort();
+}
+
+std::string cmQtAutoMocUic::AbsoluteBuildPath(
+ std::string const& relativePath) const
+{
+ std::string res(BaseConst().AutogenBuildDir);
+ res += '/';
+ res += relativePath;
+ return res;
+}
+
+std::string cmQtAutoMocUic::AbsoluteIncludePath(
+ std::string const& relativePath) const
+{
+ std::string res(BaseConst().AutogenIncludeDir);
+ res += '/';
+ res += relativePath;
+ return res;
+}
diff --git a/Source/cmQtAutoMocUic.h b/Source/cmQtAutoMocUic.h
new file mode 100644
index 000000000..8061c13e6
--- /dev/null
+++ b/Source/cmQtAutoMocUic.h
@@ -0,0 +1,576 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmQtAutoMocUic_h
+#define cmQtAutoMocUic_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmFileTime.h"
+#include "cmQtAutoGen.h"
+#include "cmQtAutoGenerator.h"
+#include "cmWorkerPool.h"
+#include "cmsys/RegularExpression.hxx"
+
+#include <atomic>
+#include <cstddef>
+#include <map>
+#include <memory> // IWYU pragma: keep
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+class cmMakefile;
+
+/** \class cmQtAutoMocUic
+ * \brief AUTOMOC and AUTOUIC generator
+ */
+class cmQtAutoMocUic : public cmQtAutoGenerator
+{
+public:
+ cmQtAutoMocUic();
+ ~cmQtAutoMocUic() override;
+
+ cmQtAutoMocUic(cmQtAutoMocUic const&) = delete;
+ cmQtAutoMocUic& operator=(cmQtAutoMocUic const&) = delete;
+
+public:
+ // -- Types
+
+ /**
+ * Search key plus regular expression pair
+ */
+ struct KeyExpT
+ {
+ KeyExpT() = default;
+
+ KeyExpT(const char* key, const char* exp)
+ : Key(key)
+ , Exp(exp)
+ {
+ }
+
+ KeyExpT(std::string key, std::string const& exp)
+ : Key(std::move(key))
+ , Exp(exp)
+ {
+ }
+
+ std::string Key;
+ cmsys::RegularExpression Exp;
+ };
+
+ /**
+ * Include string with sub parts
+ */
+ struct IncludeKeyT
+ {
+ IncludeKeyT(std::string const& key, std::size_t basePrefixLength);
+
+ std::string Key; // Full include string
+ std::string Dir; // Include directory
+ std::string Base; // Base part of the include file name
+ };
+
+ /**
+ * Source file parsing cache
+ */
+ class ParseCacheT
+ {
+ public:
+ // -- Types
+ /**
+ * Entry of the file parsing cache
+ */
+ struct FileT
+ {
+ void Clear();
+
+ struct MocT
+ {
+ std::string Macro;
+ struct IncludeT
+ {
+ std::vector<IncludeKeyT> Underscore;
+ std::vector<IncludeKeyT> Dot;
+ } Include;
+ std::vector<std::string> Depends;
+ } Moc;
+
+ struct UicT
+ {
+ std::vector<IncludeKeyT> Include;
+ std::vector<std::string> Depends;
+ } Uic;
+ };
+ typedef std::shared_ptr<FileT> FileHandleT;
+ typedef std::pair<FileHandleT, bool> GetOrInsertT;
+
+ public:
+ ParseCacheT();
+ ~ParseCacheT();
+
+ void Clear();
+
+ bool ReadFromFile(std::string const& fileName);
+ bool WriteToFile(std::string const& fileName);
+
+ //! Might return an invalid handle
+ FileHandleT Get(std::string const& fileName) const;
+ //! Always returns a valid handle
+ GetOrInsertT GetOrInsert(std::string const& fileName);
+
+ private:
+ std::unordered_map<std::string, FileHandleT> Map_;
+ };
+
+ /**
+ * Source file data
+ */
+ class SourceFileT
+ {
+ public:
+ SourceFileT(std::string fileName)
+ : FileName(std::move(fileName))
+ {
+ }
+
+ public:
+ std::string FileName;
+ cmFileTime FileTime;
+ ParseCacheT::FileHandleT ParseData;
+ std::string BuildPath;
+ bool Moc = false;
+ bool Uic = false;
+ };
+ typedef std::shared_ptr<SourceFileT> SourceFileHandleT;
+ typedef std::map<std::string, SourceFileHandleT> SourceFileMapT;
+
+ /**
+ * Meta compiler file mapping information
+ */
+ struct MappingT
+ {
+ SourceFileHandleT SourceFile;
+ std::string OutputFile;
+ std::string IncludeString;
+ std::vector<SourceFileHandleT> IncluderFiles;
+ };
+ typedef std::shared_ptr<MappingT> MappingHandleT;
+ typedef std::map<std::string, MappingHandleT> MappingMapT;
+
+ /**
+ * Common settings
+ */
+ class BaseSettingsT
+ {
+ public:
+ // -- Constructors
+ BaseSettingsT();
+ ~BaseSettingsT();
+
+ BaseSettingsT(BaseSettingsT const&) = delete;
+ BaseSettingsT& operator=(BaseSettingsT const&) = delete;
+
+ // -- Attributes
+ // - Config
+ bool MultiConfig = false;
+ bool IncludeProjectDirsBefore = false;
+ unsigned int QtVersionMajor = 4;
+ // - Directories
+ std::string ProjectSourceDir;
+ std::string ProjectBinaryDir;
+ std::string CurrentSourceDir;
+ std::string CurrentBinaryDir;
+ std::string AutogenBuildDir;
+ std::string AutogenIncludeDir;
+ // - Files
+ std::string CMakeExecutable;
+ cmFileTime CMakeExecutableTime;
+ std::string ParseCacheFile;
+ std::vector<std::string> HeaderExtensions;
+ };
+
+ /**
+ * Shared common variables
+ */
+ class BaseEvalT
+ {
+ public:
+ // -- Parse Cache
+ bool ParseCacheChanged = false;
+ cmFileTime ParseCacheTime;
+ ParseCacheT ParseCache;
+
+ // -- Sources
+ SourceFileMapT Headers;
+ SourceFileMapT Sources;
+ };
+
+ /**
+ * Moc settings
+ */
+ class MocSettingsT
+ {
+ public:
+ // -- Constructors
+ MocSettingsT();
+ ~MocSettingsT();
+
+ MocSettingsT(MocSettingsT const&) = delete;
+ MocSettingsT& operator=(MocSettingsT const&) = delete;
+
+ // -- Const methods
+ bool skipped(std::string const& fileName) const;
+ std::string MacrosString() const;
+
+ // -- Attributes
+ bool Enabled = false;
+ bool SettingsChanged = false;
+ bool RelaxedMode = false;
+ cmFileTime ExecutableTime;
+ std::string Executable;
+ std::string CompFileAbs;
+ std::string PredefsFileRel;
+ std::string PredefsFileAbs;
+ std::unordered_set<std::string> SkipList;
+ std::vector<std::string> IncludePaths;
+ std::vector<std::string> Includes;
+ std::vector<std::string> Definitions;
+ std::vector<std::string> Options;
+ std::vector<std::string> AllOptions;
+ std::vector<std::string> PredefsCmd;
+ std::vector<KeyExpT> DependFilters;
+ std::vector<KeyExpT> MacroFilters;
+ cmsys::RegularExpression RegExpInclude;
+ };
+
+ /**
+ * Moc shared variables
+ */
+ class MocEvalT
+ {
+ public:
+ // -- predefines file
+ cmFileTime PredefsTime;
+ // -- Mappings
+ MappingMapT HeaderMappings;
+ MappingMapT SourceMappings;
+ MappingMapT Includes;
+ // -- Discovered files
+ SourceFileMapT HeadersDiscovered;
+ // -- Mocs compilation
+ bool CompUpdated = false;
+ std::vector<std::string> CompFiles;
+ };
+
+ /**
+ * Uic settings
+ */
+ class UicSettingsT
+ {
+ public:
+ UicSettingsT();
+ ~UicSettingsT();
+
+ UicSettingsT(UicSettingsT const&) = delete;
+ UicSettingsT& operator=(UicSettingsT const&) = delete;
+
+ // -- Const methods
+ bool skipped(std::string const& fileName) const;
+
+ // -- Attributes
+ bool Enabled = false;
+ bool SettingsChanged = false;
+ cmFileTime ExecutableTime;
+ std::string Executable;
+ std::unordered_set<std::string> SkipList;
+ std::vector<std::string> TargetOptions;
+ std::map<std::string, std::vector<std::string>> Options;
+ std::vector<std::string> SearchPaths;
+ cmsys::RegularExpression RegExpInclude;
+ };
+
+ /**
+ * Uic shared variables
+ */
+ class UicEvalT
+ {
+ public:
+ SourceFileMapT UiFiles;
+ MappingMapT Includes;
+ };
+
+ /**
+ * Abstract job class for concurrent job processing
+ */
+ class JobT : public cmWorkerPool::JobT
+ {
+ protected:
+ /**
+ * @brief Protected default constructor
+ */
+ JobT(bool fence = false)
+ : cmWorkerPool::JobT(fence)
+ {
+ }
+
+ //! Get the generator. Only valid during Process() call!
+ cmQtAutoMocUic* Gen() const
+ {
+ return static_cast<cmQtAutoMocUic*>(UserData());
+ };
+
+ // -- Accessors. Only valid during Process() call!
+ Logger const& Log() const { return Gen()->Log(); }
+ BaseSettingsT const& BaseConst() const { return Gen()->BaseConst(); }
+ BaseEvalT& BaseEval() const { return Gen()->BaseEval(); }
+ MocSettingsT const& MocConst() const { return Gen()->MocConst(); }
+ MocEvalT& MocEval() const { return Gen()->MocEval(); }
+ UicSettingsT const& UicConst() const { return Gen()->UicConst(); }
+ UicEvalT& UicEval() const { return Gen()->UicEval(); }
+
+ // -- Error logging with automatic abort
+ void LogError(GenT genType, std::string const& message) const;
+ void LogFileError(GenT genType, std::string const& filename,
+ std::string const& message) const;
+ void LogCommandError(GenT genType, std::string const& message,
+ std::vector<std::string> const& command,
+ std::string const& output) const;
+
+ /**
+ * @brief Run an external process. Use only during Process() call!
+ */
+ bool RunProcess(GenT genType, cmWorkerPool::ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string* infoMessage = nullptr);
+ };
+
+ /**
+ * Fence job utility class
+ */
+ class JobFenceT : public JobT
+ {
+ public:
+ JobFenceT()
+ : JobT(true)
+ {
+ }
+ void Process() override{};
+ };
+
+ /**
+ * Generate moc_predefs.h
+ */
+ class JobMocPredefsT : public JobFenceT
+ {
+ void Process() override;
+ bool Update(std::string* reason) const;
+ };
+
+ /**
+ * File parse job base class
+ */
+ class JobParseT : public JobT
+ {
+ public:
+ JobParseT(SourceFileHandleT fileHandle)
+ : FileHandle(std::move(fileHandle))
+ {
+ }
+
+ protected:
+ bool ReadFile();
+ void CreateKeys(std::vector<IncludeKeyT>& container,
+ std::set<std::string> const& source,
+ std::size_t basePrefixLength);
+ void MocMacro();
+ void MocDependecies();
+ void MocIncludes();
+ void UicIncludes();
+
+ protected:
+ SourceFileHandleT FileHandle;
+ std::string Content;
+ };
+
+ /**
+ * Header file parse job
+ */
+ class JobParseHeaderT : public JobParseT
+ {
+ public:
+ using JobParseT::JobParseT;
+ void Process() override;
+ };
+
+ /**
+ * Source file parse job
+ */
+ class JobParseSourceT : public JobParseT
+ {
+ public:
+ using JobParseT::JobParseT;
+ void Process() override;
+ };
+
+ /**
+ * Evaluate parsed files
+ */
+ class JobEvaluateT : public JobFenceT
+ {
+ void Process() override;
+
+ // -- Moc
+ bool MocEvalHeader(SourceFileHandleT source);
+ bool MocEvalSource(SourceFileHandleT const& source);
+ SourceFileHandleT MocFindIncludedHeader(
+ std::string const& includerDir, std::string const& includeBase) const;
+ SourceFileHandleT MocFindHeader(std::string const& basePath) const;
+ std::string MocMessageTestHeaders(std::string const& fileBase) const;
+ bool MocRegisterIncluded(std::string const& includeString,
+ SourceFileHandleT includerFileHandle,
+ SourceFileHandleT sourceFileHandle,
+ bool sourceIsHeader) const;
+ void MocRegisterMapping(MappingHandleT mappingHandle,
+ bool sourceIsHeader) const;
+
+ // -- Uic
+ bool UicEval(SourceFileMapT const& fileMap);
+ bool UicEvalFile(SourceFileHandleT sourceFileHandle);
+ SourceFileHandleT UicFindIncludedUi(std::string const& sourceFile,
+ std::string const& sourceDir,
+ IncludeKeyT const& incKey) const;
+ bool UicRegisterMapping(std::string const& includeString,
+ SourceFileHandleT uiFileHandle,
+ SourceFileHandleT includerFileHandle);
+ };
+
+ /**
+ * Generates moc/uic jobs
+ */
+ class JobGenerateT : public JobFenceT
+ {
+ void Process() override;
+ // -- Moc
+ bool MocGenerate(MappingHandleT const& mapping, bool compFile) const;
+ bool MocUpdate(MappingT const& mapping, std::string* reason) const;
+ std::pair<std::string, cmFileTime> MocFindDependency(
+ std::string const& sourceDir, std::string const& includeString) const;
+ // -- Uic
+ bool UicGenerate(MappingHandleT const& mapping) const;
+ bool UicUpdate(MappingT const& mapping, std::string* reason) const;
+ };
+
+ /**
+ * File compiling base job
+ */
+ class JobCompileT : public JobT
+ {
+ public:
+ JobCompileT(MappingHandleT uicMapping, std::unique_ptr<std::string> reason)
+ : Mapping(std::move(uicMapping))
+ , Reason(std::move(reason))
+ {
+ }
+
+ protected:
+ MappingHandleT Mapping;
+ std::unique_ptr<std::string> Reason;
+ };
+
+ /**
+ * moc compiles a file
+ */
+ class JobMocT : public JobCompileT
+ {
+ public:
+ using JobCompileT::JobCompileT;
+ void Process() override;
+ };
+
+ /**
+ * uic compiles a file
+ */
+ class JobUicT : public JobCompileT
+ {
+ public:
+ using JobCompileT::JobCompileT;
+ void Process() override;
+ };
+
+ /// @brief Generate mocs_compilation.cpp
+ ///
+ class JobMocsCompilationT : public JobFenceT
+ {
+ private:
+ void Process() override;
+ };
+
+ /// @brief The last job
+ ///
+ class JobFinishT : public JobFenceT
+ {
+ private:
+ void Process() override;
+ };
+
+ // -- Const settings interface
+ BaseSettingsT const& BaseConst() const { return this->BaseConst_; }
+ BaseEvalT& BaseEval() { return this->BaseEval_; }
+ MocSettingsT const& MocConst() const { return this->MocConst_; }
+ MocEvalT& MocEval() { return this->MocEval_; }
+ UicSettingsT const& UicConst() const { return this->UicConst_; }
+ UicEvalT& UicEval() { return this->UicEval_; }
+
+ // -- Parallel job processing interface
+ cmWorkerPool& WorkerPool() { return WorkerPool_; }
+ void AbortError() { Abort(true); }
+ void AbortSuccess() { Abort(false); }
+
+ // -- Utility
+ std::string AbsoluteBuildPath(std::string const& relativePath) const;
+ std::string AbsoluteIncludePath(std::string const& relativePath) const;
+ template <class JOBTYPE>
+ void CreateParseJobs(SourceFileMapT const& sourceMap);
+
+private:
+ // -- Utility accessors
+ Logger const& Log() const { return Logger_; }
+ // -- Abstract processing interface
+ bool Init(cmMakefile* makefile) override;
+ void InitJobs();
+ bool Process() override;
+ // -- Settings file
+ void SettingsFileRead();
+ bool SettingsFileWrite();
+ // -- Parse cache
+ void ParseCacheRead();
+ bool ParseCacheWrite();
+ // -- Thread processing
+ void Abort(bool error);
+ // -- Generation
+ bool CreateDirectories();
+
+private:
+ // -- Utility
+ Logger Logger_;
+ // -- Settings
+ BaseSettingsT BaseConst_;
+ BaseEvalT BaseEval_;
+ MocSettingsT MocConst_;
+ MocEvalT MocEval_;
+ UicSettingsT UicConst_;
+ UicEvalT UicEval_;
+ // -- Settings file
+ std::string SettingsFile_;
+ std::string SettingsStringMoc_;
+ std::string SettingsStringUic_;
+ // -- Worker thread pool
+ std::atomic<bool> JobError_ = ATOMIC_VAR_INIT(false);
+ cmWorkerPool WorkerPool_;
+};
+
+#endif
diff --git a/Source/cmQtAutoRcc.cxx b/Source/cmQtAutoRcc.cxx
new file mode 100644
index 000000000..20885df93
--- /dev/null
+++ b/Source/cmQtAutoRcc.cxx
@@ -0,0 +1,523 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmQtAutoRcc.h"
+#include "cmQtAutoGen.h"
+
+#include <sstream>
+
+#include "cmAlgorithms.h"
+#include "cmCryptoHash.h"
+#include "cmDuration.h"
+#include "cmFileLockResult.h"
+#include "cmMakefile.h"
+#include "cmProcessOutput.h"
+#include "cmSystemTools.h"
+
+// -- Class methods
+
+cmQtAutoRcc::cmQtAutoRcc() = default;
+
+cmQtAutoRcc::~cmQtAutoRcc() = default;
+
+bool cmQtAutoRcc::Init(cmMakefile* makefile)
+{
+ // -- Utility lambdas
+ auto InfoGet = [makefile](std::string const& key) {
+ return makefile->GetSafeDefinition(key);
+ };
+ auto InfoGetList =
+ [makefile](std::string const& key) -> std::vector<std::string> {
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list);
+ return list;
+ };
+ auto InfoGetConfig = [makefile,
+ this](std::string const& key) -> std::string {
+ const char* valueConf = nullptr;
+ {
+ std::string keyConf = key;
+ keyConf += '_';
+ keyConf += InfoConfig();
+ valueConf = makefile->GetDefinition(keyConf);
+ }
+ if (valueConf == nullptr) {
+ return makefile->GetSafeDefinition(key);
+ }
+ return std::string(valueConf);
+ };
+ auto InfoGetConfigList =
+ [&InfoGetConfig](std::string const& key) -> std::vector<std::string> {
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
+ return list;
+ };
+ auto LogInfoError = [this](std::string const& msg) -> bool {
+ std::ostringstream err;
+ err << "In " << Quoted(this->InfoFile()) << ":\n" << msg;
+ this->Log().Error(GenT::RCC, err.str());
+ return false;
+ };
+
+ // -- Read info file
+ if (!makefile->ReadListFile(InfoFile())) {
+ return LogInfoError("File processing failed.");
+ }
+
+ // - Configurations
+ Logger_.RaiseVerbosity(InfoGet("ARCC_VERBOSITY"));
+ MultiConfig_ = makefile->IsOn("ARCC_MULTI_CONFIG");
+
+ // - Directories
+ AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR");
+ if (AutogenBuildDir_.empty()) {
+ return LogInfoError("Build directory empty.");
+ }
+
+ IncludeDir_ = InfoGetConfig("ARCC_INCLUDE_DIR");
+ if (IncludeDir_.empty()) {
+ return LogInfoError("Include directory empty.");
+ }
+
+ // - Rcc executable
+ RccExecutable_ = InfoGet("ARCC_RCC_EXECUTABLE");
+ if (!RccExecutableTime_.Load(RccExecutable_)) {
+ std::string error = "The rcc executable ";
+ error += Quoted(RccExecutable_);
+ error += " does not exist.";
+ return LogInfoError(error);
+ }
+ RccListOptions_ = InfoGetList("ARCC_RCC_LIST_OPTIONS");
+
+ // - Job
+ LockFile_ = InfoGet("ARCC_LOCK_FILE");
+ QrcFile_ = InfoGet("ARCC_SOURCE");
+ QrcFileName_ = cmSystemTools::GetFilenameName(QrcFile_);
+ QrcFileDir_ = cmSystemTools::GetFilenamePath(QrcFile_);
+ RccPathChecksum_ = InfoGet("ARCC_OUTPUT_CHECKSUM");
+ RccFileName_ = InfoGet("ARCC_OUTPUT_NAME");
+ Options_ = InfoGetConfigList("ARCC_OPTIONS");
+ Inputs_ = InfoGetList("ARCC_INPUTS");
+
+ // - Settings file
+ SettingsFile_ = InfoGetConfig("ARCC_SETTINGS_FILE");
+
+ // - Validity checks
+ if (LockFile_.empty()) {
+ return LogInfoError("Lock file name missing.");
+ }
+ if (SettingsFile_.empty()) {
+ return LogInfoError("Settings file name missing.");
+ }
+ if (AutogenBuildDir_.empty()) {
+ return LogInfoError("Autogen build directory missing.");
+ }
+ if (RccExecutable_.empty()) {
+ return LogInfoError("rcc executable missing.");
+ }
+ if (QrcFile_.empty()) {
+ return LogInfoError("rcc input file missing.");
+ }
+ if (RccFileName_.empty()) {
+ return LogInfoError("rcc output file missing.");
+ }
+
+ // Init derived information
+ // ------------------------
+
+ RccFilePublic_ = AutogenBuildDir_;
+ RccFilePublic_ += '/';
+ RccFilePublic_ += RccPathChecksum_;
+ RccFilePublic_ += '/';
+ RccFilePublic_ += RccFileName_;
+
+ // Compute rcc output file name
+ if (IsMultiConfig()) {
+ RccFileOutput_ = IncludeDir_;
+ RccFileOutput_ += '/';
+ RccFileOutput_ += MultiConfigOutput();
+ } else {
+ RccFileOutput_ = RccFilePublic_;
+ }
+
+ return true;
+}
+
+bool cmQtAutoRcc::Process()
+{
+ if (!SettingsFileRead()) {
+ return false;
+ }
+
+ // Test if the rcc output needs to be regenerated
+ bool generate = false;
+ if (!TestQrcRccFiles(generate)) {
+ return false;
+ }
+ if (!generate && !TestResources(generate)) {
+ return false;
+ }
+ // Generate on demand
+ if (generate) {
+ if (!GenerateRcc()) {
+ return false;
+ }
+ } else {
+ // Test if the info file is newer than the output file
+ if (!TestInfoFile()) {
+ return false;
+ }
+ }
+
+ if (!GenerateWrapper()) {
+ return false;
+ }
+
+ return SettingsFileWrite();
+}
+
+std::string cmQtAutoRcc::MultiConfigOutput() const
+{
+ static std::string const suffix = "_CMAKE_";
+ std::string res;
+ res += RccPathChecksum_;
+ res += '/';
+ res += AppendFilenameSuffix(RccFileName_, suffix);
+ return res;
+}
+
+bool cmQtAutoRcc::SettingsFileRead()
+{
+ // Compose current settings strings
+ {
+ cmCryptoHash crypt(cmCryptoHash::AlgoSHA256);
+ std::string const sep(" ~~~ ");
+ {
+ std::string str;
+ str += RccExecutable_;
+ str += sep;
+ str += cmJoin(RccListOptions_, ";");
+ str += sep;
+ str += QrcFile_;
+ str += sep;
+ str += RccPathChecksum_;
+ str += sep;
+ str += RccFileName_;
+ str += sep;
+ str += cmJoin(Options_, ";");
+ str += sep;
+ str += cmJoin(Inputs_, ";");
+ str += sep;
+ SettingsString_ = crypt.HashString(str);
+ }
+ }
+
+ // Make sure the settings file exists
+ if (!cmSystemTools::FileExists(SettingsFile_, true)) {
+ // Touch the settings file to make sure it exists
+ if (!cmSystemTools::Touch(SettingsFile_, true)) {
+ Log().ErrorFile(GenT::RCC, SettingsFile_,
+ "Settings file creation failed.");
+ return false;
+ }
+ }
+
+ // Lock the lock file
+ {
+ // Make sure the lock file exists
+ if (!cmSystemTools::FileExists(LockFile_, true)) {
+ if (!cmSystemTools::Touch(LockFile_, true)) {
+ Log().ErrorFile(GenT::RCC, LockFile_, "Lock file creation failed.");
+ return false;
+ }
+ }
+ // Lock the lock file
+ cmFileLockResult lockResult =
+ LockFileLock_.Lock(LockFile_, static_cast<unsigned long>(-1));
+ if (!lockResult.IsOk()) {
+ Log().ErrorFile(GenT::RCC, LockFile_,
+ "File lock failed: " + lockResult.GetOutputMessage());
+ return false;
+ }
+ }
+
+ // Read old settings
+ {
+ std::string content;
+ if (FileRead(content, SettingsFile_)) {
+ SettingsChanged_ = (SettingsString_ != SettingsFind(content, "rcc"));
+ // In case any setting changed clear the old settings file.
+ // This triggers a full rebuild on the next run if the current
+ // build is aborted before writing the current settings in the end.
+ if (SettingsChanged_) {
+ std::string error;
+ if (!FileWrite(SettingsFile_, "", &error)) {
+ Log().ErrorFile(GenT::RCC, SettingsFile_,
+ "Settings file clearing failed. " + error);
+ return false;
+ }
+ }
+ } else {
+ SettingsChanged_ = true;
+ }
+ }
+
+ return true;
+}
+
+bool cmQtAutoRcc::SettingsFileWrite()
+{
+ // Only write if any setting changed
+ if (SettingsChanged_) {
+ if (Log().Verbose()) {
+ Log().Info(GenT::RCC, "Writing settings file " + Quoted(SettingsFile_));
+ }
+ // Write settings file
+ std::string content = "rcc:";
+ content += SettingsString_;
+ content += '\n';
+ std::string error;
+ if (!FileWrite(SettingsFile_, content, &error)) {
+ Log().ErrorFile(GenT::RCC, SettingsFile_,
+ "Settings file writing failed. " + error);
+ // Remove old settings file to trigger a full rebuild on the next run
+ cmSystemTools::RemoveFile(SettingsFile_);
+ return false;
+ }
+ }
+
+ // Unlock the lock file
+ LockFileLock_.Release();
+ return true;
+}
+
+/// Do basic checks if rcc generation is required
+bool cmQtAutoRcc::TestQrcRccFiles(bool& generate)
+{
+ // Test if the rcc input file exists
+ if (!QrcFileTime_.Load(QrcFile_)) {
+ std::string error;
+ error = "The resources file ";
+ error += Quoted(QrcFile_);
+ error += " does not exist";
+ Log().ErrorFile(GenT::RCC, QrcFile_, error);
+ return false;
+ }
+
+ // Test if the rcc output file exists
+ if (!RccFileTime_.Load(RccFileOutput_)) {
+ if (Log().Verbose()) {
+ Reason = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because it doesn't exist, from ";
+ Reason += Quoted(QrcFile_);
+ }
+ generate = true;
+ return true;
+ }
+
+ // Test if the settings changed
+ if (SettingsChanged_) {
+ if (Log().Verbose()) {
+ Reason = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because the rcc settings changed, from ";
+ Reason += Quoted(QrcFile_);
+ }
+ generate = true;
+ return true;
+ }
+
+ // Test if the rcc output file is older than the .qrc file
+ if (RccFileTime_.Older(QrcFileTime_)) {
+ if (Log().Verbose()) {
+ Reason = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because it is older than ";
+ Reason += Quoted(QrcFile_);
+ Reason += ", from ";
+ Reason += Quoted(QrcFile_);
+ }
+ generate = true;
+ return true;
+ }
+
+ // Test if the rcc output file is older than the rcc executable
+ if (RccFileTime_.Older(RccExecutableTime_)) {
+ if (Log().Verbose()) {
+ Reason = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because it is older than the rcc executable, from ";
+ Reason += Quoted(QrcFile_);
+ }
+ generate = true;
+ return true;
+ }
+
+ return true;
+}
+
+bool cmQtAutoRcc::TestResources(bool& generate)
+{
+ // Read resource files list
+ if (Inputs_.empty()) {
+ std::string error;
+ RccLister const lister(RccExecutable_, RccListOptions_);
+ if (!lister.list(QrcFile_, Inputs_, error, Log().Verbose())) {
+ Log().ErrorFile(GenT::RCC, QrcFile_, error);
+ return false;
+ }
+ }
+
+ // Check if any resource file is newer than the rcc output file
+ for (std::string const& resFile : Inputs_) {
+ // Check if the resource file exists
+ cmFileTime fileTime;
+ if (!fileTime.Load(resFile)) {
+ std::string error;
+ error = "Could not find the resource file\n ";
+ error += Quoted(resFile);
+ error += '\n';
+ Log().ErrorFile(GenT::RCC, QrcFile_, error);
+ return false;
+ }
+ // Check if the resource file is newer than the rcc output file
+ if (RccFileTime_.Older(fileTime)) {
+ if (Log().Verbose()) {
+ Reason = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because it is older than ";
+ Reason += Quoted(resFile);
+ Reason += ", from ";
+ Reason += Quoted(QrcFile_);
+ }
+ generate = true;
+ break;
+ }
+ }
+ return true;
+}
+
+bool cmQtAutoRcc::TestInfoFile()
+{
+ // Test if the rcc output file is older than the info file
+ if (RccFileTime_.Older(InfoFileTime())) {
+ if (Log().Verbose()) {
+ std::string reason = "Touching ";
+ reason += Quoted(RccFileOutput_);
+ reason += " because it is older than ";
+ reason += Quoted(InfoFile());
+ Log().Info(GenT::RCC, reason);
+ }
+ // Touch build file
+ if (!cmSystemTools::Touch(RccFileOutput_, false)) {
+ Log().ErrorFile(GenT::RCC, RccFileOutput_, "Build file touch failed");
+ return false;
+ }
+ BuildFileChanged_ = true;
+ }
+
+ return true;
+}
+
+bool cmQtAutoRcc::GenerateRcc()
+{
+ // Make parent directory
+ if (!MakeParentDirectory(RccFileOutput_)) {
+ Log().ErrorFile(GenT::RCC, RccFileOutput_,
+ "Could not create parent directory");
+ return false;
+ }
+
+ // Compose rcc command
+ std::vector<std::string> cmd;
+ cmd.push_back(RccExecutable_);
+ cmAppend(cmd, Options_);
+ cmd.emplace_back("-o");
+ cmd.push_back(RccFileOutput_);
+ cmd.push_back(QrcFile_);
+
+ // Log reason and command
+ if (Log().Verbose()) {
+ std::string msg = Reason;
+ if (!msg.empty() && (msg.back() != '\n')) {
+ msg += '\n';
+ }
+ msg += QuotedCommand(cmd);
+ msg += '\n';
+ Log().Info(GenT::RCC, msg);
+ }
+
+ std::string rccStdOut;
+ std::string rccStdErr;
+ int retVal = 0;
+ bool result = cmSystemTools::RunSingleCommand(
+ cmd, &rccStdOut, &rccStdErr, &retVal, AutogenBuildDir_.c_str(),
+ cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto);
+ if (!result || (retVal != 0)) {
+ // rcc process failed
+ {
+ std::string err = "The rcc process failed to compile\n ";
+ err += Quoted(QrcFile_);
+ err += "\ninto\n ";
+ err += Quoted(RccFileOutput_);
+ Log().ErrorCommand(GenT::RCC, err, cmd, rccStdOut + rccStdErr);
+ }
+ cmSystemTools::RemoveFile(RccFileOutput_);
+ return false;
+ }
+
+ // rcc process success
+ // Print rcc output
+ if (!rccStdOut.empty()) {
+ Log().Info(GenT::RCC, rccStdOut);
+ }
+ BuildFileChanged_ = true;
+
+ return true;
+}
+
+bool cmQtAutoRcc::GenerateWrapper()
+{
+ // Generate a wrapper source file on demand
+ if (IsMultiConfig()) {
+ // Wrapper file content
+ std::string content;
+ content += "// This is an autogenerated configuration wrapper file.\n";
+ content += "// Changes will be overwritten.\n";
+ content += "#include <";
+ content += MultiConfigOutput();
+ content += ">\n";
+
+ // Compare with existing file content
+ bool fileDiffers = true;
+ {
+ std::string oldContents;
+ if (FileRead(oldContents, RccFilePublic_)) {
+ fileDiffers = (oldContents != content);
+ }
+ }
+ if (fileDiffers) {
+ // Write new wrapper file
+ if (Log().Verbose()) {
+ Log().Info(GenT::RCC, "Generating RCC wrapper file " + RccFilePublic_);
+ }
+ std::string error;
+ if (!FileWrite(RccFilePublic_, content, &error)) {
+ Log().ErrorFile(GenT::RCC, RccFilePublic_,
+ "RCC wrapper file writing failed. " + error);
+ return false;
+ }
+ } else if (BuildFileChanged_) {
+ // Just touch the wrapper file
+ if (Log().Verbose()) {
+ Log().Info(GenT::RCC, "Touching RCC wrapper file " + RccFilePublic_);
+ }
+ if (!cmSystemTools::Touch(RccFilePublic_, false)) {
+ Log().ErrorFile(GenT::RCC, RccFilePublic_,
+ "RCC wrapper file touch failed.");
+ return false;
+ }
+ }
+ }
+ return true;
+}
diff --git a/Source/cmQtAutoGeneratorRcc.h b/Source/cmQtAutoRcc.h
index 1ec1c4a8c..636a6672d 100644
--- a/Source/cmQtAutoGeneratorRcc.h
+++ b/Source/cmQtAutoRcc.h
@@ -1,13 +1,13 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
-#ifndef cmQtAutoGeneratorRcc_h
-#define cmQtAutoGeneratorRcc_h
+#ifndef cmQtAutoRcc_h
+#define cmQtAutoRcc_h
#include "cmConfigure.h" // IWYU pragma: keep
#include "cmFileLock.h"
+#include "cmFileTime.h"
#include "cmQtAutoGenerator.h"
-#include "cm_uv.h"
#include <string>
#include <vector>
@@ -15,62 +15,38 @@
class cmMakefile;
// @brief AUTORCC generator
-class cmQtAutoGeneratorRcc : public cmQtAutoGenerator
+class cmQtAutoRcc : public cmQtAutoGenerator
{
public:
- cmQtAutoGeneratorRcc();
- ~cmQtAutoGeneratorRcc() override;
+ cmQtAutoRcc();
+ ~cmQtAutoRcc() override;
- cmQtAutoGeneratorRcc(cmQtAutoGeneratorRcc const&) = delete;
- cmQtAutoGeneratorRcc& operator=(cmQtAutoGeneratorRcc const&) = delete;
+ cmQtAutoRcc(cmQtAutoRcc const&) = delete;
+ cmQtAutoRcc& operator=(cmQtAutoRcc const&) = delete;
private:
- // -- Types
-
- /// @brief Processing stage
- enum class StageT : unsigned char
- {
- SETTINGS_READ,
- TEST_QRC_RCC_FILES,
- TEST_RESOURCES_READ,
- TEST_RESOURCES,
- TEST_INFO_FILE,
- GENERATE,
- GENERATE_RCC,
- GENERATE_WRAPPER,
- SETTINGS_WRITE,
- FINISH,
- END
- };
+ // -- Utility
+ Logger const& Log() const { return Logger_; }
+ bool IsMultiConfig() const { return MultiConfig_; }
+ std::string MultiConfigOutput() const;
// -- Abstract processing interface
bool Init(cmMakefile* makefile) override;
bool Process() override;
- // -- Process stage
- static void UVPollStage(uv_async_t* handle);
- void PollStage();
- void SetStage(StageT stage);
// -- Settings file
bool SettingsFileRead();
- void SettingsFileWrite();
+ bool SettingsFileWrite();
// -- Tests
- bool TestQrcRccFiles();
- bool TestResourcesRead();
- bool TestResources();
- void TestInfoFile();
+ bool TestQrcRccFiles(bool& generate);
+ bool TestResources(bool& generate);
+ bool TestInfoFile();
// -- Generation
- void GenerateParentDir();
bool GenerateRcc();
- void GenerateWrapper();
-
- // -- Utility
- bool IsMultiConfig() const { return MultiConfig_; }
- std::string MultiConfigOutput() const;
- bool StartProcess(std::string const& workingDirectory,
- std::vector<std::string> const& command,
- bool mergedOutput);
+ bool GenerateWrapper();
private:
+ // -- Logging
+ Logger Logger_;
// -- Config settings
bool MultiConfig_ = false;
// -- Directories
@@ -78,6 +54,7 @@ private:
std::string IncludeDir_;
// -- Qt environment
std::string RccExecutable_;
+ cmFileTime RccExecutableTime_;
std::vector<std::string> RccListOptions_;
// -- Job
std::string LockFile_;
@@ -85,23 +62,19 @@ private:
std::string QrcFile_;
std::string QrcFileName_;
std::string QrcFileDir_;
+ cmFileTime QrcFileTime_;
std::string RccPathChecksum_;
std::string RccFileName_;
std::string RccFileOutput_;
std::string RccFilePublic_;
+ cmFileTime RccFileTime_;
+ std::string Reason;
std::vector<std::string> Options_;
std::vector<std::string> Inputs_;
- // -- Subprocess
- ProcessResultT ProcessResult_;
- std::unique_ptr<ReadOnlyProcessT> Process_;
// -- Settings file
std::string SettingsFile_;
std::string SettingsString_;
bool SettingsChanged_ = false;
- // -- libuv loop
- StageT Stage_ = StageT::SETTINGS_READ;
- bool Error_ = false;
- bool Generate_ = false;
bool BuildFileChanged_ = false;
};
diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx
index 55204d708..2064275e7 100644
--- a/Source/cmRST.cxx
+++ b/Source/cmRST.cxx
@@ -3,6 +3,7 @@
#include "cmRST.h"
#include "cmAlgorithms.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
#include "cmVersion.h"
@@ -32,7 +33,7 @@ cmRST::cmRST(std::ostream& os, std::string docroot)
, TocTreeDirective("^.. toctree::[ \t]*(.*)$")
, ProductionListDirective("^.. productionlist::[ \t]*(.*)$")
, NoteDirective("^.. note::[ \t]*(.*)$")
- , ModuleRST("^#\\[(=*)\\[\\.rst:$")
+ , ModuleRST(R"(^#\[(=*)\[\.rst:$)")
, CMakeRole("(:cmake)?:("
"command|cpack_gen|generator|variable|envvar|module|policy|"
"prop_cache|prop_dir|prop_gbl|prop_inst|prop_sf|"
@@ -456,6 +457,12 @@ void cmRST::UnindentLines(std::vector<std::string>& lines)
size_t trailingEmpty =
std::distance(rit, cmFindNot(cmReverseRange(lines), std::string()));
+ if ((leadingEmpty + trailingEmpty) >= lines.size()) {
+ // All lines are empty. The markup block is empty. Leave only one.
+ lines.resize(1);
+ return;
+ }
+
std::vector<std::string>::iterator contentEnd = cmRotate(
lines.begin(), lines.begin() + leadingEmpty, lines.end() - trailingEmpty);
lines.erase(contentEnd, lines.end());
diff --git a/Source/cmRange.h b/Source/cmRange.h
new file mode 100644
index 000000000..3be5193e7
--- /dev/null
+++ b/Source/cmRange.h
@@ -0,0 +1,239 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmRange_h
+#define cmRange_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+
+namespace RangeIterators {
+
+template <typename Iter, typename UnaryPredicate>
+class FilterIterator
+{
+public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = typename std::iterator_traits<Iter>::value_type;
+ using difference_type = typename std::iterator_traits<Iter>::difference_type;
+ using pointer = typename std::iterator_traits<Iter>::pointer;
+ using reference = typename std::iterator_traits<Iter>::reference;
+
+ FilterIterator(Iter b, Iter e, UnaryPredicate p)
+ : Cur(std::move(b))
+ , End(std::move(e))
+ , Pred(std::move(p))
+ {
+ this->SatisfyPredicate();
+ }
+
+ FilterIterator& operator++()
+ {
+ ++this->Cur;
+ this->SatisfyPredicate();
+ return *this;
+ }
+
+ FilterIterator& operator--()
+ {
+ do {
+ --this->Cur;
+ } while (!this->Pred(*this->Cur));
+ return *this;
+ }
+
+ bool operator==(FilterIterator const& other) const
+ {
+ return this->Cur == other.Cur;
+ }
+
+ bool operator!=(FilterIterator const& other) const
+ {
+ return !this->operator==(other);
+ }
+
+ auto operator*() const -> decltype(*std::declval<Iter>())
+ {
+ return *this->Cur;
+ }
+
+private:
+ void SatisfyPredicate()
+ {
+ while (this->Cur != this->End && !this->Pred(*this->Cur)) {
+ ++this->Cur;
+ }
+ }
+
+ Iter Cur;
+ Iter End;
+ UnaryPredicate Pred;
+};
+
+template <typename Iter, typename UnaryFunction>
+class TransformIterator
+{
+public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type =
+ typename std::remove_cv<typename std::remove_reference<decltype(
+ std::declval<UnaryFunction>()(*std::declval<Iter>()))>::type>::type;
+ using difference_type = typename std::iterator_traits<Iter>::difference_type;
+ using pointer = value_type const*;
+ using reference = value_type const&;
+
+ TransformIterator(Iter i, UnaryFunction f)
+ : Base(std::move(i))
+ , Func(std::move(f))
+ {
+ }
+
+ TransformIterator& operator++()
+ {
+ ++this->Base;
+ return *this;
+ }
+
+ TransformIterator& operator--()
+ {
+ --this->Base;
+ return *this;
+ }
+
+ bool operator==(TransformIterator const& other) const
+ {
+ return this->Base == other.Base;
+ }
+
+ bool operator!=(TransformIterator const& other) const
+ {
+ return !this->operator==(other);
+ }
+
+ auto operator*() const
+ -> decltype(std::declval<UnaryFunction>()(*std::declval<Iter>()))
+ {
+ return this->Func(*this->Base);
+ }
+
+private:
+ Iter Base;
+ UnaryFunction Func;
+};
+
+} // namespace RangeIterators
+
+template <typename Iter>
+class cmRange
+{
+public:
+ using const_iterator = Iter;
+ using value_type = typename std::iterator_traits<Iter>::value_type;
+ using difference_type = typename std::iterator_traits<Iter>::difference_type;
+
+ cmRange(Iter b, Iter e)
+ : Begin(std::move(b))
+ , End(std::move(e))
+ {
+ }
+
+ Iter begin() const { return this->Begin; }
+ Iter end() const { return this->End; }
+ bool empty() const { return this->Begin == this->End; }
+
+ difference_type size() const
+ {
+ return std::distance(this->Begin, this->End);
+ }
+
+ cmRange& advance(difference_type amount) &
+ {
+ std::advance(this->Begin, amount);
+ return *this;
+ }
+
+ cmRange advance(difference_type amount) &&
+ {
+ std::advance(this->Begin, amount);
+ return std::move(*this);
+ }
+
+ cmRange& retreat(difference_type amount) &
+ {
+ std::advance(this->End, -amount);
+ return *this;
+ }
+
+ cmRange retreat(difference_type amount) &&
+ {
+ std::advance(this->End, -amount);
+ return std::move(*this);
+ }
+
+ template <typename UnaryPredicate>
+ bool all_of(UnaryPredicate p) const
+ {
+ return std::all_of(this->Begin, this->End, std::ref(p));
+ }
+
+ template <typename UnaryPredicate>
+ bool any_of(UnaryPredicate p) const
+ {
+ return std::any_of(this->Begin, this->End, std::ref(p));
+ }
+
+ template <typename UnaryPredicate>
+ bool none_of(UnaryPredicate p) const
+ {
+ return std::none_of(this->Begin, this->End, std::ref(p));
+ }
+
+ template <typename UnaryPredicate>
+ auto filter(UnaryPredicate p) const
+ -> cmRange<RangeIterators::FilterIterator<Iter, UnaryPredicate>>
+ {
+ using It = RangeIterators::FilterIterator<Iter, UnaryPredicate>;
+ return { It(this->Begin, this->End, p), It(this->End, this->End, p) };
+ }
+
+ template <typename UnaryFunction>
+ auto transform(UnaryFunction f) const
+ -> cmRange<RangeIterators::TransformIterator<Iter, UnaryFunction>>
+ {
+ using It = RangeIterators::TransformIterator<Iter, UnaryFunction>;
+ return { It(this->Begin, f), It(this->End, f) };
+ }
+
+private:
+ Iter Begin;
+ Iter End;
+};
+
+template <typename Iter1, typename Iter2>
+bool operator==(cmRange<Iter1> const& left, cmRange<Iter2> const& right)
+{
+ return left.size() == right.size() &&
+ std::equal(left.begin(), left.end(), right.begin());
+}
+
+template <typename Iter1, typename Iter2>
+auto cmMakeRange(Iter1 begin, Iter2 end) -> cmRange<Iter1>
+{
+ return { begin, end };
+}
+
+template <typename Range>
+auto cmMakeRange(Range const& range) -> cmRange<decltype(range.begin())>
+{
+ return { range.begin(), range.end() };
+}
+
+template <typename Range>
+auto cmReverseRange(Range const& range) -> cmRange<decltype(range.rbegin())>
+{
+ return { range.rbegin(), range.rend() };
+}
+
+#endif
diff --git a/Source/cmRemoveCommand.cxx b/Source/cmRemoveCommand.cxx
index bb14e687d..a64ad8c7d 100644
--- a/Source/cmRemoveCommand.cxx
+++ b/Source/cmRemoveCommand.cxx
@@ -25,15 +25,13 @@ bool cmRemoveCommand::InitialPass(std::vector<std::string> const& args,
}
// expand the variable
- std::vector<std::string> varArgsExpanded;
- cmSystemTools::ExpandListArgument(cacheValue, varArgsExpanded);
+ std::vector<std::string> const varArgsExpanded =
+ cmSystemTools::ExpandedListArgument(cacheValue);
// expand the args
// check for REMOVE(VAR v1 v2 ... vn)
- std::vector<std::string> argsExpanded;
- std::vector<std::string> temp;
- temp.insert(temp.end(), args.begin() + 1, args.end());
- cmSystemTools::ExpandList(temp, argsExpanded);
+ std::vector<std::string> const argsExpanded =
+ cmSystemTools::ExpandedLists(args.begin() + 1, args.end());
// now create the new value
std::string value;
diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx
index e347a2cf5..33389cad5 100644
--- a/Source/cmRulePlaceholderExpander.cxx
+++ b/Source/cmRulePlaceholderExpander.cxx
@@ -91,6 +91,31 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable(
if (replaceValues.Includes && variable == "INCLUDES") {
return replaceValues.Includes;
}
+ if (replaceValues.SwiftLibraryName) {
+ if (variable == "SWIFT_LIBRARY_NAME") {
+ return replaceValues.SwiftLibraryName;
+ }
+ }
+ if (replaceValues.SwiftModule) {
+ if (variable == "SWIFT_MODULE") {
+ return replaceValues.SwiftModule;
+ }
+ }
+ if (replaceValues.SwiftModuleName) {
+ if (variable == "SWIFT_MODULE_NAME") {
+ return replaceValues.SwiftModuleName;
+ }
+ }
+ if (replaceValues.SwiftOutputFileMap) {
+ if (variable == "SWIFT_OUTPUT_FILE_MAP") {
+ return replaceValues.SwiftOutputFileMap;
+ }
+ }
+ if (replaceValues.SwiftSources) {
+ if (variable == "SWIFT_SOURCES") {
+ return replaceValues.SwiftSources;
+ }
+ }
if (replaceValues.TargetPDB) {
if (variable == "TARGET_PDB") {
return replaceValues.TargetPDB;
@@ -162,16 +187,6 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable(
}
}
}
- if (replaceValues.SwiftAuxiliarySources) {
- if (variable == "SWIFT_AUXILIARY_SOURCES") {
- return replaceValues.SwiftAuxiliarySources;
- }
- }
- if (replaceValues.SwiftModuleName) {
- if (variable == "SWIFT_MODULE_NAME") {
- return replaceValues.SwiftModuleName;
- }
- }
if (variable == "TARGET_SONAME" || variable == "SONAME_FLAG" ||
variable == "TARGET_INSTALLNAME_DIR") {
// All these variables depend on TargetSOName
diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h
index 5c0363729..8f361967b 100644
--- a/Source/cmRulePlaceholderExpander.h
+++ b/Source/cmRulePlaceholderExpander.h
@@ -58,8 +58,11 @@ public:
const char* Includes;
const char* DependencyFile;
const char* FilterPrefix;
- const char* SwiftAuxiliarySources;
+ const char* SwiftLibraryName;
+ const char* SwiftModule;
const char* SwiftModuleName;
+ const char* SwiftOutputFileMap;
+ const char* SwiftSources;
};
// Expand rule variables in CMake of the type found in language rules
diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx
index 0f51e0eb6..f98984ed6 100644
--- a/Source/cmSearchPath.cxx
+++ b/Source/cmSearchPath.cxx
@@ -144,7 +144,7 @@ void cmSearchPath::AddSuffixes(const std::vector<std::string>& suffixes)
// this will get incorrectly considered a network
// path on windows and cause huge delays.
std::string p = inPath;
- if (!p.empty() && *p.rbegin() != '/') {
+ if (!p.empty() && p.back() != '/') {
p += "/";
}
@@ -176,7 +176,7 @@ void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths,
for (std::string const& path : paths) {
std::string dir = path;
- if (!subdir.empty() && !dir.empty() && *dir.rbegin() != '/') {
+ if (!subdir.empty() && !dir.empty() && dir.back() != '/') {
dir += "/";
}
if (subdir == "include" || subdir == "lib") {
diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx
index e740c0519..1903fd917 100644
--- a/Source/cmServer.cxx
+++ b/Source/cmServer.cxx
@@ -97,13 +97,13 @@ void cmServer::ProcessRequest(cmConnection* connection,
}
cmSystemTools::SetMessageCallback(
- [&request](const char* msg, const char* title) {
+ [&request](const std::string& msg, const char* title) {
reportMessage(msg, title, request);
});
if (this->Protocol) {
this->Protocol->CMakeInstance()->SetProgressCallback(
- [&request](const char* msg, float prog) {
+ [&request](const std::string& msg, float prog) {
reportProgress(msg, prog, request);
});
this->WriteResponse(connection, this->Protocol->Process(request),
@@ -155,7 +155,7 @@ void cmServer::PrintHello(cmConnection* connection) const
this->WriteJsonObject(connection, hello, nullptr);
}
-void cmServer::reportProgress(const char* msg, float progress,
+void cmServer::reportProgress(const std::string& msg, float progress,
const cmServerRequest& request)
{
if (progress < 0.0f || progress > 1.0f) {
@@ -165,15 +165,14 @@ void cmServer::reportProgress(const char* msg, float progress,
}
}
-void cmServer::reportMessage(const char* msg, const char* title,
+void cmServer::reportMessage(const std::string& msg, const char* title,
const cmServerRequest& request)
{
- assert(msg);
std::string titleString;
if (title) {
titleString = title;
}
- request.ReportMessage(std::string(msg), titleString);
+ request.ReportMessage(msg, titleString);
}
cmServerResponse cmServer::SetProtocolVersion(const cmServerRequest& request)
diff --git a/Source/cmServer.h b/Source/cmServer.h
index e1ed27a0c..aba4924c9 100644
--- a/Source/cmServer.h
+++ b/Source/cmServer.h
@@ -119,9 +119,9 @@ public:
void OnConnected(cmConnection* connection) override;
private:
- static void reportProgress(const char* msg, float progress,
+ static void reportProgress(const std::string& msg, float progress,
const cmServerRequest& request);
- static void reportMessage(const char* msg, const char* title,
+ static void reportMessage(const std::string& msg, const char* title,
const cmServerRequest& request);
// Handle requests:
diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx
index 844a85890..a878890da 100644
--- a/Source/cmServerConnection.cxx
+++ b/Source/cmServerConnection.cxx
@@ -29,7 +29,7 @@ cm::uv_stream_ptr cmStdIoConnection::SetupStream(int file_id)
tty.init(*this->Server->GetLoop(), file_id, file_id == 0,
static_cast<cmEventBasedConnection*>(this));
uv_tty_set_mode(tty, UV_TTY_MODE_NORMAL);
- return std::move(tty);
+ return { std::move(tty) };
}
case UV_FILE:
if (file_id == 0) {
@@ -43,7 +43,7 @@ cm::uv_stream_ptr cmStdIoConnection::SetupStream(int file_id)
pipe.init(*this->Server->GetLoop(), 0,
static_cast<cmEventBasedConnection*>(this));
uv_pipe_open(pipe, file_id);
- return std::move(pipe);
+ return { std::move(pipe) };
}
default:
assert(false && "Unable to determine stream type");
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index 203ee93e4..558391f30 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -8,6 +8,7 @@
#include "cmGlobalGenerator.h"
#include "cmJsonObjectDictionary.h"
#include "cmJsonObjects.h"
+#include "cmMessageType.h"
#include "cmServer.h"
#include "cmServerDictionary.h"
#include "cmState.h"
@@ -600,6 +601,10 @@ cmServerResponse cmServerProtocol1::ProcessConfigure(
}
int ret = cm->Configure();
+ cm->IssueMessage(
+ MessageType::DEPRECATION_WARNING,
+ "The 'cmake-server(7)' is deprecated. "
+ "Please port clients to use the 'cmake-file-api(7)' instead.");
if (ret < 0) {
return request.ReportError("Configuration failed.");
}
@@ -625,7 +630,7 @@ cmServerResponse cmServerProtocol1::ProcessGlobalSettings(
Json::Value obj = Json::objectValue;
// Capabilities information:
- obj[kCAPABILITIES_KEY] = cm->ReportCapabilitiesJson(true);
+ obj[kCAPABILITIES_KEY] = cm->ReportCapabilitiesJson();
obj[kDEBUG_OUTPUT_KEY] = cm->GetDebugOutput();
obj[kTRACE_KEY] = cm->GetTrace();
diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx
index 6bd071cfb..41555e8e3 100644
--- a/Source/cmSetCommand.cxx
+++ b/Source/cmSetCommand.cxx
@@ -5,6 +5,7 @@
#include "cmAlgorithms.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
index 3c4111bc1..e9343c7db 100644
--- a/Source/cmSetPropertyCommand.cxx
+++ b/Source/cmSetPropertyCommand.cxx
@@ -8,6 +8,7 @@
#include "cmInstalledFile.h"
#include "cmMakefile.h"
#include "cmProperty.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmState.h"
#include "cmSystemTools.h"
@@ -33,25 +34,25 @@ bool cmSetPropertyCommand::InitialPass(std::vector<std::string> const& args,
}
// Get the scope on which to set the property.
- std::vector<std::string>::const_iterator arg = args.begin();
+ std::string const& scopeName = args.front();
cmProperty::ScopeType scope;
- if (*arg == "GLOBAL") {
+ if (scopeName == "GLOBAL") {
scope = cmProperty::GLOBAL;
- } else if (*arg == "DIRECTORY") {
+ } else if (scopeName == "DIRECTORY") {
scope = cmProperty::DIRECTORY;
- } else if (*arg == "TARGET") {
+ } else if (scopeName == "TARGET") {
scope = cmProperty::TARGET;
- } else if (*arg == "SOURCE") {
+ } else if (scopeName == "SOURCE") {
scope = cmProperty::SOURCE_FILE;
- } else if (*arg == "TEST") {
+ } else if (scopeName == "TEST") {
scope = cmProperty::TEST;
- } else if (*arg == "CACHE") {
+ } else if (scopeName == "CACHE") {
scope = cmProperty::CACHE;
- } else if (*arg == "INSTALL") {
+ } else if (scopeName == "INSTALL") {
scope = cmProperty::INSTALL;
} else {
std::ostringstream e;
- e << "given invalid scope " << *arg << ". "
+ e << "given invalid scope " << scopeName << ". "
<< "Valid scopes are GLOBAL, DIRECTORY, "
"TARGET, SOURCE, TEST, CACHE, INSTALL.";
this->SetError(e.str());
@@ -68,32 +69,32 @@ bool cmSetPropertyCommand::InitialPass(std::vector<std::string> const& args,
};
Doing doing = DoingNames;
const char* sep = "";
- for (++arg; arg != args.end(); ++arg) {
- if (*arg == "PROPERTY") {
+ for (std::string const& arg : cmMakeRange(args).advance(1)) {
+ if (arg == "PROPERTY") {
doing = DoingProperty;
- } else if (*arg == "APPEND") {
+ } else if (arg == "APPEND") {
doing = DoingNone;
this->AppendMode = true;
this->Remove = false;
this->AppendAsString = false;
- } else if (*arg == "APPEND_STRING") {
+ } else if (arg == "APPEND_STRING") {
doing = DoingNone;
this->AppendMode = true;
this->Remove = false;
this->AppendAsString = true;
} else if (doing == DoingNames) {
- this->Names.insert(*arg);
+ this->Names.insert(arg);
} else if (doing == DoingProperty) {
- this->PropertyName = *arg;
+ this->PropertyName = arg;
doing = DoingValues;
} else if (doing == DoingValues) {
this->PropertyValue += sep;
sep = ";";
- this->PropertyValue += *arg;
+ this->PropertyValue += arg;
this->Remove = false;
} else {
std::ostringstream e;
- e << "given invalid argument \"" << *arg << "\".";
+ e << "given invalid argument \"" << arg << "\".";
this->SetError(e.str());
return false;
}
@@ -334,7 +335,7 @@ bool cmSetPropertyCommand::HandleCacheMode()
!cmSystemTools::IsOff(this->PropertyValue)) {
std::ostringstream e;
e << "given non-boolean value \"" << this->PropertyValue
- << "\" for CACHE property \"ADVANCED\". ";
+ << R"(" for CACHE property "ADVANCED". )";
this->SetError(e.str());
return false;
}
diff --git a/Source/cmSetTargetPropertiesCommand.cxx b/Source/cmSetTargetPropertiesCommand.cxx
index 642591337..1dc7e69a3 100644
--- a/Source/cmSetTargetPropertiesCommand.cxx
+++ b/Source/cmSetTargetPropertiesCommand.cxx
@@ -4,6 +4,7 @@
#include <iterator>
+#include "cmAlgorithms.h"
#include "cmMakefile.h"
#include "cmTarget.h"
@@ -30,7 +31,7 @@ bool cmSetTargetPropertiesCommand::InitialPass(
this->SetError("called with incorrect number of arguments.");
return false;
}
- propertyPairs.insert(propertyPairs.end(), j, args.end());
+ cmAppend(propertyPairs, j, args.end());
break;
}
numFiles++;
diff --git a/Source/cmSetTestsPropertiesCommand.cxx b/Source/cmSetTestsPropertiesCommand.cxx
index e27c675c6..cc9587ca6 100644
--- a/Source/cmSetTestsPropertiesCommand.cxx
+++ b/Source/cmSetTestsPropertiesCommand.cxx
@@ -4,6 +4,7 @@
#include <iterator>
+#include "cmAlgorithms.h"
#include "cmMakefile.h"
#include "cmTest.h"
@@ -30,7 +31,7 @@ bool cmSetTestsPropertiesCommand::InitialPass(
this->SetError("called with incorrect number of arguments.");
return false;
}
- propertyPairs.insert(propertyPairs.end(), j, args.end());
+ cmAppend(propertyPairs, j, args.end());
break;
}
numFiles++;
diff --git a/Source/cmSiteNameCommand.cxx b/Source/cmSiteNameCommand.cxx
index 01758ee3a..9f041bc5f 100644
--- a/Source/cmSiteNameCommand.cxx
+++ b/Source/cmSiteNameCommand.cxx
@@ -52,9 +52,8 @@ bool cmSiteNameCommand::InitialPass(std::vector<std::string> const& args,
// try to find the hostname for this computer
if (!cmSystemTools::IsOff(hostname_cmd)) {
std::string host;
- cmSystemTools::RunSingleCommand(hostname_cmd.c_str(), &host, nullptr,
- nullptr, nullptr,
- cmSystemTools::OUTPUT_NONE);
+ cmSystemTools::RunSingleCommand(hostname_cmd, &host, nullptr, nullptr,
+ nullptr, cmSystemTools::OUTPUT_NONE);
// got the hostname
if (!host.empty()) {
diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h
index a82a58aa9..edad4c7b5 100644
--- a/Source/cmSourceFile.h
+++ b/Source/cmSourceFile.h
@@ -34,6 +34,9 @@ public:
~cmSourceFile();
+ cmSourceFile(const cmSourceFile&) = delete;
+ cmSourceFile& operator=(const cmSourceFile&) = delete;
+
/**
* Get the list of the custom commands for this source file
*/
@@ -41,13 +44,13 @@ public:
cmCustomCommand const* GetCustomCommand() const;
void SetCustomCommand(cmCustomCommand* cc);
- ///! Set/Get a property of this source file
+ //! Set/Get a property of this source file
void SetProperty(const std::string& prop, const char* value);
void AppendProperty(const std::string& prop, const char* value,
bool asString = false);
- ///! Might return a nullptr if the property is not set or invalid
+ //! Might return a nullptr if the property is not set or invalid
const char* GetProperty(const std::string& prop) const;
- ///! Always returns a valid pointer
+ //! Always returns a valid pointer
const char* GetSafeProperty(const std::string& prop) const;
bool GetPropertyAsBool(const std::string& prop) const;
@@ -55,7 +58,7 @@ public:
command like get_property or get_source_file_property. */
const char* GetPropertyForUser(const std::string& prop);
- ///! Checks is the GENERATED property is set and true
+ //! Checks is the GENERATED property is set and true
/// @return Equivalent to GetPropertyAsBool("GENERATED")
bool GetIsGenerated() const { return this->IsGenerated; }
diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx
index 34ded3890..5cdacaaf8 100644
--- a/Source/cmSourceGroupCommand.cxx
+++ b/Source/cmSourceGroupCommand.cxx
@@ -77,9 +77,13 @@ std::vector<std::string> prepareFilesPathsForTree(
const std::string& currentSourceDir)
{
std::vector<std::string> prepared;
+ prepared.reserve(filesPaths.size());
for (auto const& filePath : filesPaths) {
- prepared.push_back(prepareFilePathForTree(filePath, currentSourceDir));
+ // If provided file path is actually not a file, silently ignore it.
+ if (cmSystemTools::FileExists(filePath, /*isFile=*/true)) {
+ prepared.push_back(prepareFilePathForTree(filePath, currentSourceDir));
+ }
}
return prepared;
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index a08e9b8ba..fa7df0b2c 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -556,9 +556,28 @@ const char* cmState::GetGlobalProperty(const std::string& prop)
if (prop == "CMAKE_C_KNOWN_FEATURES") {
return &FOR_EACH_C_FEATURE(STRING_LIST_ELEMENT)[1];
}
+ if (prop == "CMAKE_C90_KNOWN_FEATURES") {
+ return &FOR_EACH_C90_FEATURE(STRING_LIST_ELEMENT)[1];
+ }
+ if (prop == "CMAKE_C99_KNOWN_FEATURES") {
+ return &FOR_EACH_C99_FEATURE(STRING_LIST_ELEMENT)[1];
+ }
+ if (prop == "CMAKE_C11_KNOWN_FEATURES") {
+ return &FOR_EACH_C11_FEATURE(STRING_LIST_ELEMENT)[1];
+ }
if (prop == "CMAKE_CXX_KNOWN_FEATURES") {
return &FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT)[1];
}
+ if (prop == "CMAKE_CXX98_KNOWN_FEATURES") {
+ return &FOR_EACH_CXX98_FEATURE(STRING_LIST_ELEMENT)[1];
+ }
+ if (prop == "CMAKE_CXX11_KNOWN_FEATURES") {
+ return &FOR_EACH_CXX11_FEATURE(STRING_LIST_ELEMENT)[1];
+ }
+ if (prop == "CMAKE_CXX14_KNOWN_FEATURES") {
+ return &FOR_EACH_CXX14_FEATURE(STRING_LIST_ELEMENT)[1];
+ }
+
#undef STRING_LIST_ELEMENT
return this->GlobalProperties.GetPropertyValue(prop);
}
diff --git a/Source/cmState.h b/Source/cmState.h
index f755f8362..6abe71c0b 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -35,6 +35,9 @@ public:
cmState();
~cmState();
+ cmState(const cmState&) = delete;
+ cmState& operator=(const cmState&) = delete;
+
enum Mode
{
Unknown,
@@ -104,7 +107,7 @@ public:
void RemoveCacheEntryProperty(std::string const& key,
std::string const& propertyName);
- ///! Break up a line like VAR:type="value" into var, type and value
+ //! Break up a line like VAR:type="value" into var, type and value
static bool ParseCacheEntry(const std::string& entry, std::string& var,
std::string& value,
cmStateEnums::CacheEntryType& type);
diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx
index 6752743a1..182d3fe73 100644
--- a/Source/cmStateDirectory.cxx
+++ b/Source/cmStateDirectory.cxx
@@ -8,8 +8,10 @@
#include <iterator>
#include <utility>
+#include "cmAlgorithms.h"
#include "cmProperty.h"
#include "cmPropertyMap.h"
+#include "cmRange.h"
#include "cmState.h"
#include "cmStatePrivate.h"
#include "cmStateTypes.h"
@@ -40,9 +42,8 @@ void cmStateDirectory::ComputeRelativePathTopSource()
std::string result = snapshots.front().GetDirectory().GetCurrentSource();
- for (std::vector<cmStateSnapshot>::const_iterator it = snapshots.begin() + 1;
- it != snapshots.end(); ++it) {
- std::string currentSource = it->GetDirectory().GetCurrentSource();
+ for (cmStateSnapshot const& snp : cmMakeRange(snapshots).advance(1)) {
+ std::string currentSource = snp.GetDirectory().GetCurrentSource();
if (cmSystemTools::IsSubDirectory(result, currentSource)) {
result = currentSource;
}
@@ -66,9 +67,8 @@ void cmStateDirectory::ComputeRelativePathTopBinary()
std::string result = snapshots.front().GetDirectory().GetCurrentBinary();
- for (std::vector<cmStateSnapshot>::const_iterator it = snapshots.begin() + 1;
- it != snapshots.end(); ++it) {
- std::string currentBinary = it->GetDirectory().GetCurrentBinary();
+ for (cmStateSnapshot const& snp : cmMakeRange(snapshots).advance(1)) {
+ std::string currentBinary = snp.GetDirectory().GetCurrentBinary();
if (cmSystemTools::IsSubDirectory(result, currentBinary)) {
result = currentBinary;
}
@@ -621,9 +621,7 @@ const char* cmStateDirectory::GetProperty(const std::string& prop,
}
if (prop == "VARIABLES") {
std::vector<std::string> res = this->Snapshot_.ClosureKeys();
- std::vector<std::string> cacheKeys =
- this->Snapshot_.State->GetCacheEntryKeys();
- res.insert(res.end(), cacheKeys.begin(), cacheKeys.end());
+ cmAppend(res, this->Snapshot_.State->GetCacheEntryKeys());
std::sort(res.begin(), res.end());
output = cmJoin(res, ";");
return output.c_str();
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index 91d619020..998f90415 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -1,9 +1,13 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
+#define _SCL_SECURE_NO_WARNINGS
+
#include "cmStringCommand.h"
#include "cmsys/RegularExpression.hxx"
+#include <algorithm>
#include <ctype.h>
+#include <iterator>
#include <memory> // IWYU pragma: keep
#include <sstream>
#include <stdio.h>
@@ -13,6 +17,8 @@
#include "cmCryptoHash.h"
#include "cmGeneratorExpression.h"
#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmStringReplaceHelper.h"
#include "cmSystemTools.h"
#include "cmTimestamp.h"
@@ -78,6 +84,9 @@ bool cmStringCommand::InitialPass(std::vector<std::string> const& args,
if (subCommand == "STRIP") {
return this->HandleStripCommand(args);
}
+ if (subCommand == "REPEAT") {
+ return this->HandleRepeatCommand(args);
+ }
if (subCommand == "RANDOM") {
return this->HandleRandomCommand(args);
}
@@ -708,6 +717,59 @@ bool cmStringCommand::HandleStripCommand(std::vector<std::string> const& args)
return true;
}
+bool cmStringCommand::HandleRepeatCommand(std::vector<std::string> const& args)
+{
+ // `string(REPEAT "<str>" <times> OUTPUT_VARIABLE)`
+ enum ArgPos : std::size_t
+ {
+ SUB_COMMAND,
+ VALUE,
+ TIMES,
+ OUTPUT_VARIABLE,
+ TOTAL_ARGS
+ };
+
+ if (args.size() != ArgPos::TOTAL_ARGS) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "sub-command REPEAT requires three arguments.");
+ return true;
+ }
+
+ unsigned long times;
+ if (!cmSystemTools::StringToULong(args[ArgPos::TIMES].c_str(), &times)) {
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ "repeat count is not a positive number.");
+ return true;
+ }
+
+ const auto& stringValue = args[ArgPos::VALUE];
+ const auto& variableName = args[ArgPos::OUTPUT_VARIABLE];
+ const auto inStringLength = stringValue.size();
+
+ std::string result;
+ switch (inStringLength) {
+ case 0u:
+ // Nothing to do for zero length input strings
+ break;
+ case 1u:
+ // NOTE If the string to repeat consists of the only character,
+ // use the appropriate constructor.
+ result = std::string(times, stringValue[0]);
+ break;
+ default:
+ result = std::string(inStringLength * times, char{});
+ for (auto i = 0u; i < times; ++i) {
+ std::copy(cm::cbegin(stringValue), cm::cend(stringValue),
+ &result[i * inStringLength]);
+ }
+ break;
+ }
+
+ this->Makefile->AddDefinition(variableName, result.c_str());
+ return true;
+}
+
bool cmStringCommand::HandleRandomCommand(std::vector<std::string> const& args)
{
if (args.size() < 2 || args.size() == 3 || args.size() == 5) {
@@ -771,7 +833,7 @@ bool cmStringCommand::HandleRandomCommand(std::vector<std::string> const& args)
}
result.push_back(0);
- this->Makefile->AddDefinition(variableName, &*result.begin());
+ this->Makefile->AddDefinition(variableName, result.data());
return true;
}
diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h
index cbff73e99..acde60549 100644
--- a/Source/cmStringCommand.h
+++ b/Source/cmStringCommand.h
@@ -51,6 +51,7 @@ protected:
bool HandleConcatCommand(std::vector<std::string> const& args);
bool HandleJoinCommand(std::vector<std::string> const& args);
bool HandleStripCommand(std::vector<std::string> const& args);
+ bool HandleRepeatCommand(std::vector<std::string> const& args);
bool HandleRandomCommand(std::vector<std::string> const& args);
bool HandleFindCommand(std::vector<std::string> const& args);
bool HandleTimestampCommand(std::vector<std::string> const& args);
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 1d20e2f1a..15014811e 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -5,7 +5,7 @@
#include "cmAlgorithms.h"
#include "cmDuration.h"
#include "cmProcessOutput.h"
-#include "cm_sys_stat.h"
+#include "cmRange.h"
#include "cm_uv.h"
#if defined(CMAKE_BUILD_WITH_CMAKE)
@@ -42,6 +42,7 @@
#include <assert.h>
#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
#include <iostream>
#include <sstream>
#include <stdio.h>
@@ -55,12 +56,9 @@
# include <windows.h>
// include wincrypt.h after windows.h
# include <wincrypt.h>
-
-# include <fcntl.h> /* _O_TEXT */
#else
# include <sys/time.h>
# include <unistd.h>
-# include <utime.h>
#endif
#if defined(_WIN32) && \
@@ -90,18 +88,6 @@ static bool cm_isspace(char c)
return ((c & 0x80) == 0) && isspace(c);
}
-class cmSystemToolsFileTime
-{
-public:
-#if defined(_WIN32) && !defined(__CYGWIN__)
- FILETIME timeCreation;
- FILETIME timeLastAccess;
- FILETIME timeLastWrite;
-#else
- struct utimbuf timeBuf;
-#endif
-};
-
#if !defined(HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE)
// For GetEnvironmentVariables
# if defined(_WIN32)
@@ -134,29 +120,6 @@ static int cm_archive_read_open_file(struct archive* a, const char* file,
#endif
#ifdef _WIN32
-class cmSystemToolsWindowsHandle
-{
-public:
- cmSystemToolsWindowsHandle(HANDLE h)
- : handle_(h)
- {
- }
- ~cmSystemToolsWindowsHandle()
- {
- if (this->handle_ != INVALID_HANDLE_VALUE) {
- CloseHandle(this->handle_);
- }
- }
- explicit operator bool() const
- {
- return this->handle_ != INVALID_HANDLE_VALUE;
- }
- bool operator!() const { return this->handle_ == INVALID_HANDLE_VALUE; }
- operator HANDLE() const { return this->handle_; }
-
-private:
- HANDLE handle_;
-};
#elif defined(__APPLE__)
# include <crt_externs.h>
@@ -167,7 +130,6 @@ bool cmSystemTools::s_RunCommandHideConsole = false;
bool cmSystemTools::s_DisableRunCommandOutput = false;
bool cmSystemTools::s_ErrorOccured = false;
bool cmSystemTools::s_FatalErrorOccured = false;
-bool cmSystemTools::s_DisableMessages = false;
bool cmSystemTools::s_ForceUnixPaths = false;
// replace replace with with as many times as it shows up in source.
@@ -250,26 +212,6 @@ std::string cmSystemTools::TrimWhitespace(const std::string& s)
return std::string(start, stop + 1);
}
-void cmSystemTools::Error(const char* m1, const char* m2, const char* m3,
- const char* m4)
-{
- std::string message = "CMake Error: ";
- if (m1) {
- message += m1;
- }
- if (m2) {
- message += m2;
- }
- if (m3) {
- message += m3;
- }
- if (m4) {
- message += m4;
- }
- cmSystemTools::s_ErrorOccured = true;
- cmSystemTools::Message(message, "Error");
-}
-
void cmSystemTools::Error(const std::string& m)
{
std::string message = "CMake Error: " + m;
@@ -323,16 +265,13 @@ void cmSystemTools::Stdout(const std::string& s)
}
}
-void cmSystemTools::Message(const char* m1, const char* title)
+void cmSystemTools::Message(const std::string& m, const char* title)
{
- if (s_DisableMessages) {
- return;
- }
if (s_MessageCallback) {
- s_MessageCallback(m1, title);
- return;
+ s_MessageCallback(m, title);
+ } else {
+ std::cerr << m << std::endl;
}
- std::cerr << m1 << std::endl << std::flush;
}
void cmSystemTools::ReportLastSystemError(const char* msg)
@@ -521,6 +460,8 @@ public:
}
free(this->ArgV);
}
+ cmSystemToolsArgV(const cmSystemToolsArgV&) = delete;
+ cmSystemToolsArgV& operator=(const cmSystemToolsArgV&) = delete;
void Store(std::vector<std::string>& args) const
{
for (char** arg = this->ArgV; arg && *arg; ++arg) {
@@ -533,7 +474,7 @@ void cmSystemTools::ParseUnixCommandLine(const char* command,
std::vector<std::string>& args)
{
// Invoke the underlying parser.
- cmSystemToolsArgV argv = cmsysSystem_Parse_CommandForUnix(command, 0);
+ cmSystemToolsArgV argv(cmsysSystem_Parse_CommandForUnix(command, 0));
argv.Store(args);
}
@@ -542,8 +483,7 @@ std::vector<std::string> cmSystemTools::HandleResponseFile(
std::vector<std::string>::const_iterator argEnd)
{
std::vector<std::string> arg_full;
- for (std::vector<std::string>::const_iterator a = argBeg; a != argEnd; ++a) {
- std::string const& arg = *a;
+ for (std::string const& arg : cmMakeRange(argBeg, argEnd)) {
if (cmHasLiteralPrefix(arg, "@")) {
cmsys::ifstream responseFile(arg.substr(1).c_str(), std::ios::in);
if (!responseFile) {
@@ -561,7 +501,7 @@ std::vector<std::string> cmSystemTools::HandleResponseFile(
#else
cmSystemTools::ParseUnixCommandLine(line.c_str(), args2);
#endif
- arg_full.insert(arg_full.end(), args2.begin(), args2.end());
+ cmAppend(arg_full, args2);
}
} else {
arg_full.push_back(arg);
@@ -570,13 +510,14 @@ std::vector<std::string> cmSystemTools::HandleResponseFile(
return arg_full;
}
-std::vector<std::string> cmSystemTools::ParseArguments(const char* command)
+std::vector<std::string> cmSystemTools::ParseArguments(const std::string& cmd)
{
std::vector<std::string> args;
std::string arg;
bool win_path = false;
+ const char* command = cmd.c_str();
if (command[0] && command[1] &&
((command[0] != '/' && command[1] == ':' && command[2] == '\\') ||
(command[0] == '\"' && command[1] != '/' && command[2] == ':' &&
@@ -740,7 +681,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
argv.push_back(nullptr);
cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
+ cmsysProcess_SetCommand(cp, argv.data());
cmsysProcess_SetWorkingDirectory(cp, dir);
if (cmSystemTools::GetRunCommandHideConsole()) {
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
@@ -785,7 +726,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
cmSystemTools::Stdout(strdata);
}
if (captureStdOut) {
- tempStdOut.insert(tempStdOut.end(), data, data + length);
+ cmAppend(tempStdOut, data, data + length);
}
} else if (pipe == cmsysProcess_Pipe_STDERR) {
if (outputflag != OUTPUT_NONE) {
@@ -793,7 +734,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
cmSystemTools::Stderr(strdata);
}
if (captureStdErr) {
- tempStdErr.insert(tempStdErr.end(), data, data + length);
+ cmAppend(tempStdErr, data, data + length);
}
}
}
@@ -867,7 +808,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
return result;
}
-bool cmSystemTools::RunSingleCommand(const char* command,
+bool cmSystemTools::RunSingleCommand(const std::string& command,
std::string* captureStdOut,
std::string* captureStdErr, int* retVal,
const char* dir, OutputOption outputflag,
@@ -897,7 +838,7 @@ std::string cmSystemTools::PrintSingleCommand(
}
bool cmSystemTools::DoesFileExistWithExtensions(
- const char* name, const std::vector<std::string>& headerExts)
+ const std::string& name, const std::vector<std::string>& headerExts)
{
std::string hname;
@@ -912,9 +853,9 @@ bool cmSystemTools::DoesFileExistWithExtensions(
return false;
}
-std::string cmSystemTools::FileExistsInParentDirectories(const char* fname,
- const char* directory,
- const char* toplevel)
+std::string cmSystemTools::FileExistsInParentDirectories(
+ const std::string& fname, const std::string& directory,
+ const std::string& toplevel)
{
std::string file = fname;
cmSystemTools::ConvertToUnixSlashes(file);
@@ -926,7 +867,7 @@ std::string cmSystemTools::FileExistsInParentDirectories(const char* fname,
if (cmSystemTools::FileExists(path)) {
return path;
}
- if (dir.size() < strlen(toplevel)) {
+ if (dir.size() < toplevel.size()) {
break;
}
prevDir = dir;
@@ -935,12 +876,6 @@ std::string cmSystemTools::FileExistsInParentDirectories(const char* fname,
return "";
}
-bool cmSystemTools::cmCopyFile(const std::string& source,
- const std::string& destination)
-{
- return Superclass::CopyFileAlways(source, destination);
-}
-
#ifdef _WIN32
cmSystemTools::WindowsFileRetry cmSystemTools::GetWindowsFileRetry()
{
@@ -1216,17 +1151,8 @@ void cmSystemTools::GlobDirs(const std::string& path,
}
}
-void cmSystemTools::ExpandList(std::vector<std::string> const& arguments,
- std::vector<std::string>& newargs)
-{
- std::vector<std::string>::const_iterator i;
- for (i = arguments.begin(); i != arguments.end(); ++i) {
- cmSystemTools::ExpandListArgument(*i, newargs);
- }
-}
-
void cmSystemTools::ExpandListArgument(const std::string& arg,
- std::vector<std::string>& newargs,
+ std::vector<std::string>& argsOut,
bool emptyArgs)
{
// If argument is empty, it is an empty list.
@@ -1235,7 +1161,7 @@ void cmSystemTools::ExpandListArgument(const std::string& arg,
}
// if there are no ; in the name then just copy the current string
if (arg.find(';') == std::string::npos) {
- newargs.push_back(arg);
+ argsOut.push_back(arg);
return;
}
std::string newArg;
@@ -1269,7 +1195,7 @@ void cmSystemTools::ExpandListArgument(const std::string& arg,
last = c + 1;
if (!newArg.empty() || emptyArgs) {
// Add the last argument if the string is not empty.
- newargs.push_back(newArg);
+ argsOut.push_back(newArg);
newArg.clear();
}
}
@@ -1282,10 +1208,18 @@ void cmSystemTools::ExpandListArgument(const std::string& arg,
newArg.append(last);
if (!newArg.empty() || emptyArgs) {
// Add the last argument if the string is not empty.
- newargs.push_back(newArg);
+ argsOut.push_back(newArg);
}
}
+std::vector<std::string> cmSystemTools::ExpandedListArgument(
+ const std::string& arg, bool emptyArgs)
+{
+ std::vector<std::string> argsOut;
+ ExpandListArgument(arg, argsOut, emptyArgs);
+ return argsOut;
+}
+
bool cmSystemTools::SimpleGlob(const std::string& glob,
std::vector<std::string>& files,
int type /* = 0 */)
@@ -1389,14 +1323,6 @@ cmSystemTools::FileFormat cmSystemTools::GetFileFormat(std::string const& ext)
return cmSystemTools::UNKNOWN_FILE_FORMAT;
}
-bool cmSystemTools::Split(const char* s, std::vector<std::string>& l)
-{
- std::vector<std::string> temp;
- bool res = Superclass::Split(s, temp);
- l.insert(l.end(), temp.begin(), temp.end());
- return res;
-}
-
std::string cmSystemTools::ConvertToOutputPath(std::string const& path)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
@@ -1424,7 +1350,7 @@ void cmSystemTools::ConvertToOutputSlashes(std::string& path)
#endif
}
-std::string cmSystemTools::ConvertToRunCommandPath(const char* path)
+std::string cmSystemTools::ConvertToRunCommandPath(const std::string& path)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
return cmSystemTools::ConvertToWindowsOutputPath(path);
@@ -1438,12 +1364,12 @@ std::string cmSystemTools::RelativePath(std::string const& local,
std::string const& remote)
{
if (!cmSystemTools::FileIsFullPath(local)) {
- cmSystemTools::Error("RelativePath must be passed a full path to local: ",
- local.c_str());
+ cmSystemTools::Error("RelativePath must be passed a full path to local: " +
+ local);
}
if (!cmSystemTools::FileIsFullPath(remote)) {
- cmSystemTools::Error("RelativePath must be passed a full path to remote: ",
- remote.c_str());
+ cmSystemTools::Error(
+ "RelativePath must be passed a full path to remote: " + remote);
}
return cmsys::SystemTools::RelativePath(local, remote);
}
@@ -1522,36 +1448,6 @@ std::string cmSystemTools::ForceToRelativePath(std::string const& local_path,
return relative;
}
-std::string cmSystemTools::CollapseCombinedPath(std::string const& dir,
- std::string const& file)
-{
- if (dir.empty() || dir == ".") {
- return file;
- }
-
- std::vector<std::string> dirComponents;
- std::vector<std::string> fileComponents;
- cmSystemTools::SplitPath(dir, dirComponents);
- cmSystemTools::SplitPath(file, fileComponents);
-
- if (fileComponents.empty()) {
- return dir;
- }
- if (!fileComponents[0].empty()) {
- // File is not a relative path.
- return file;
- }
-
- std::vector<std::string>::iterator i = fileComponents.begin() + 1;
- while (i != fileComponents.end() && *i == ".." && dirComponents.size() > 1) {
- ++i; // Remove ".." file component.
- dirComponents.pop_back(); // Remove last dir component.
- }
-
- dirComponents.insert(dirComponents.end(), i, fileComponents.end());
- return cmSystemTools::JoinPath(dirComponents);
-}
-
#ifdef CMAKE_BUILD_WITH_CMAKE
bool cmSystemTools::UnsetEnv(const char* value)
{
@@ -1627,13 +1523,13 @@ void cmSystemTools::EnableVSConsoleOutput()
#endif
}
-bool cmSystemTools::IsPathToFramework(const char* path)
+bool cmSystemTools::IsPathToFramework(const std::string& path)
{
return (cmSystemTools::FileIsFullPath(path) &&
cmHasLiteralSuffix(path, ".framework"));
}
-bool cmSystemTools::CreateTar(const char* outFileName,
+bool cmSystemTools::CreateTar(const std::string& outFileName,
const std::vector<std::string>& files,
cmTarCompression compressType, bool verbose,
std::string const& mtime,
@@ -1641,7 +1537,7 @@ bool cmSystemTools::CreateTar(const char* outFileName,
{
#if defined(CMAKE_BUILD_WITH_CMAKE)
std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
- cmsys::ofstream fout(outFileName, std::ios::out | std::ios::binary);
+ cmsys::ofstream fout(outFileName.c_str(), std::ios::out | std::ios::binary);
if (!fout) {
std::string e = "Cannot open output file \"";
e += outFileName;
@@ -1661,6 +1557,9 @@ bool cmSystemTools::CreateTar(const char* outFileName,
case TarCompressXZ:
compress = cmArchiveWrite::CompressXZ;
break;
+ case TarCompressZstd:
+ compress = cmArchiveWrite::CompressZstd;
+ break;
case TarCompressNone:
compress = cmArchiveWrite::CompressNone;
break;
@@ -1670,20 +1569,18 @@ bool cmSystemTools::CreateTar(const char* outFileName,
a.SetMTime(mtime);
a.SetVerbose(verbose);
+ bool tarCreatedSuccessfully = true;
for (auto path : files) {
if (cmSystemTools::FileIsFullPath(path)) {
// Get the relative path to the file.
path = cmSystemTools::RelativePath(cwd, path);
}
if (!a.Add(path)) {
- break;
+ cmSystemTools::Error(a.GetError());
+ tarCreatedSuccessfully = false;
}
}
- if (!a) {
- cmSystemTools::Error(a.GetError());
- return false;
- }
- return true;
+ return tarCreatedSuccessfully;
#else
(void)outFileName;
(void)files;
@@ -1795,6 +1692,16 @@ void list_item_verbose(FILE* out, struct archive_entry* entry)
fflush(out);
}
+void ArchiveError(const char* m1, struct archive* a)
+{
+ std::string message(m1);
+ const char* m2 = archive_error_string(a);
+ if (m2) {
+ message += m2;
+ }
+ cmSystemTools::Error(message);
+}
+
bool la_diagnostic(struct archive* ar, __LA_SSIZE_T r)
{
// See archive.h definition of ARCHIVE_OK for return values.
@@ -1853,7 +1760,9 @@ bool copy_data(struct archive* ar, struct archive* aw)
# endif
}
-bool extract_tar(const char* outFileName, bool verbose, bool extract)
+bool extract_tar(const std::string& outFileName,
+ const std::vector<std::string>& files, bool verbose,
+ bool extract)
{
cmLocaleRAII localeRAII;
static_cast<void>(localeRAII);
@@ -1862,10 +1771,24 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
archive_read_support_filter_all(a);
archive_read_support_format_all(a);
struct archive_entry* entry;
- int r = cm_archive_read_open_file(a, outFileName, 10240);
+
+ struct archive* matching = archive_match_new();
+ if (matching == nullptr) {
+ cmSystemTools::Error("Out of memory");
+ return false;
+ }
+
+ for (const auto& filename : files) {
+ if (archive_match_include_pattern(matching, filename.c_str()) !=
+ ARCHIVE_OK) {
+ cmSystemTools::Error("Failed to add to inclusion list: " + filename);
+ return false;
+ }
+ }
+
+ int r = cm_archive_read_open_file(a, outFileName.c_str(), 10240);
if (r) {
- cmSystemTools::Error("Problem with archive_read_open_file(): ",
- archive_error_string(a));
+ ArchiveError("Problem with archive_read_open_file(): ", a);
archive_write_free(ext);
archive_read_close(a);
return false;
@@ -1876,10 +1799,14 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
break;
}
if (r != ARCHIVE_OK) {
- cmSystemTools::Error("Problem with archive_read_next_header(): ",
- archive_error_string(a));
+ ArchiveError("Problem with archive_read_next_header(): ", a);
break;
}
+
+ if (archive_match_excluded(matching, entry)) {
+ continue;
+ }
+
if (verbose) {
if (extract) {
cmSystemTools::Stdout("x ");
@@ -1895,8 +1822,7 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
if (extract) {
r = archive_write_disk_set_options(ext, ARCHIVE_EXTRACT_TIME);
if (r != ARCHIVE_OK) {
- cmSystemTools::Error("Problem with archive_write_disk_set_options(): ",
- archive_error_string(ext));
+ ArchiveError("Problem with archive_write_disk_set_options(): ", ext);
break;
}
@@ -1907,8 +1833,7 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
}
r = archive_write_finish_entry(ext);
if (r != ARCHIVE_OK) {
- cmSystemTools::Error("Problem with archive_write_finish_entry(): ",
- archive_error_string(ext));
+ ArchiveError("Problem with archive_write_finish_entry(): ", ext);
break;
}
}
@@ -1920,14 +1845,34 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
}
# endif
else {
- cmSystemTools::Error("Problem with archive_write_header(): ",
- archive_error_string(ext));
- cmSystemTools::Error("Current file: ",
- cm_archive_entry_pathname(entry).c_str());
+ ArchiveError("Problem with archive_write_header(): ", ext);
+ cmSystemTools::Error("Current file: " +
+ cm_archive_entry_pathname(entry));
break;
}
}
}
+
+ bool error_occured = false;
+ if (matching != nullptr) {
+ const char* p;
+ int ar;
+
+ while ((ar = archive_match_path_unmatched_inclusions_next(matching, &p)) ==
+ ARCHIVE_OK) {
+ cmSystemTools::Error("tar: " + std::string(p) +
+ ": Not found in archive");
+ error_occured = true;
+ }
+ if (error_occured) {
+ return false;
+ }
+ if (ar == ARCHIVE_FATAL) {
+ cmSystemTools::Error("tar: Out of memory");
+ return false;
+ }
+ }
+ archive_match_free(matching);
archive_write_free(ext);
archive_read_close(a);
archive_read_free(a);
@@ -1936,23 +1881,29 @@ bool extract_tar(const char* outFileName, bool verbose, bool extract)
}
#endif
-bool cmSystemTools::ExtractTar(const char* outFileName, bool verbose)
+bool cmSystemTools::ExtractTar(const std::string& outFileName,
+ const std::vector<std::string>& files,
+ bool verbose)
{
#if defined(CMAKE_BUILD_WITH_CMAKE)
- return extract_tar(outFileName, verbose, true);
+ return extract_tar(outFileName, files, verbose, true);
#else
(void)outFileName;
+ (void)files;
(void)verbose;
return false;
#endif
}
-bool cmSystemTools::ListTar(const char* outFileName, bool verbose)
+bool cmSystemTools::ListTar(const std::string& outFileName,
+ const std::vector<std::string>& files,
+ bool verbose)
{
#if defined(CMAKE_BUILD_WITH_CMAKE)
- return extract_tar(outFileName, verbose, false);
+ return extract_tar(outFileName, files, verbose, false);
#else
(void)outFileName;
+ (void)files;
(void)verbose;
return false;
#endif
@@ -2018,26 +1969,26 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
processOutput.DecodeText(data, length, strdata, 1);
// Append to the stdout buffer.
std::vector<char>::size_type size = out.size();
- out.insert(out.end(), strdata.begin(), strdata.end());
+ cmAppend(out, strdata);
outiter = out.begin() + size;
} else if (pipe == cmsysProcess_Pipe_STDERR) {
processOutput.DecodeText(data, length, strdata, 2);
// Append to the stderr buffer.
std::vector<char>::size_type size = err.size();
- err.insert(err.end(), strdata.begin(), strdata.end());
+ cmAppend(err, strdata);
erriter = err.begin() + size;
} else if (pipe == cmsysProcess_Pipe_None) {
// Both stdout and stderr pipes have broken. Return leftover data.
processOutput.DecodeText(std::string(), strdata, 1);
if (!strdata.empty()) {
std::vector<char>::size_type size = out.size();
- out.insert(out.end(), strdata.begin(), strdata.end());
+ cmAppend(out, strdata);
outiter = out.begin() + size;
}
processOutput.DecodeText(std::string(), strdata, 2);
if (!strdata.empty()) {
std::vector<char>::size_type size = err.size();
- err.insert(err.end(), strdata.begin(), strdata.end());
+ cmAppend(err, strdata);
erriter = err.begin() + size;
}
if (!out.empty()) {
@@ -2055,6 +2006,71 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
}
}
+#ifdef _WIN32
+static void EnsureStdPipe(DWORD fd)
+{
+ if (GetStdHandle(fd) != INVALID_HANDLE_VALUE) {
+ return;
+ }
+ SECURITY_ATTRIBUTES sa;
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ HANDLE h = CreateFileW(
+ L"NUL",
+ fd == STD_INPUT_HANDLE ? FILE_GENERIC_READ
+ : FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ LPSTR message = NULL;
+ DWORD size = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&message, 0, NULL);
+ std::string msg = std::string(message, size);
+ LocalFree(message);
+ std::cerr << "failed to open NUL for missing stdio pipe: " << msg;
+ abort();
+ }
+
+ SetStdHandle(fd, h);
+}
+
+void cmSystemTools::EnsureStdPipes()
+{
+ EnsureStdPipe(STD_INPUT_HANDLE);
+ EnsureStdPipe(STD_OUTPUT_HANDLE);
+ EnsureStdPipe(STD_ERROR_HANDLE);
+}
+#else
+static void EnsureStdPipe(int fd)
+{
+ if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) {
+ return;
+ }
+
+ int f = open("/dev/null", fd == STDIN_FILENO ? O_RDONLY : O_WRONLY);
+ if (f == -1) {
+ perror("failed to open /dev/null for missing stdio pipe");
+ abort();
+ }
+ if (f != fd) {
+ dup2(f, fd);
+ close(f);
+ }
+}
+
+void cmSystemTools::EnsureStdPipes()
+{
+ EnsureStdPipe(STDIN_FILENO);
+ EnsureStdPipe(STDOUT_FILENO);
+ EnsureStdPipe(STDERR_FILENO);
+}
+#endif
+
void cmSystemTools::DoNotInheritStdPipes()
{
#ifdef _WIN32
@@ -2082,88 +2098,6 @@ void cmSystemTools::DoNotInheritStdPipes()
#endif
}
-bool cmSystemTools::CopyFileTime(const char* fromFile, const char* toFile)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
- cmSystemToolsWindowsHandle hFrom = CreateFileW(
- SystemTools::ConvertToWindowsExtendedPath(fromFile).c_str(), GENERIC_READ,
- FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
- cmSystemToolsWindowsHandle hTo = CreateFileW(
- SystemTools::ConvertToWindowsExtendedPath(toFile).c_str(),
- FILE_WRITE_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
- if (!hFrom || !hTo) {
- return false;
- }
- FILETIME timeCreation;
- FILETIME timeLastAccess;
- FILETIME timeLastWrite;
- if (!GetFileTime(hFrom, &timeCreation, &timeLastAccess, &timeLastWrite)) {
- return false;
- }
- return SetFileTime(hTo, &timeCreation, &timeLastAccess, &timeLastWrite) != 0;
-#else
- struct stat fromStat;
- if (stat(fromFile, &fromStat) < 0) {
- return false;
- }
-
- struct utimbuf buf;
- buf.actime = fromStat.st_atime;
- buf.modtime = fromStat.st_mtime;
- return utime(toFile, &buf) >= 0;
-#endif
-}
-
-cmSystemToolsFileTime* cmSystemTools::FileTimeNew()
-{
- return new cmSystemToolsFileTime;
-}
-
-void cmSystemTools::FileTimeDelete(cmSystemToolsFileTime* t)
-{
- delete t;
-}
-
-bool cmSystemTools::FileTimeGet(const char* fname, cmSystemToolsFileTime* t)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
- cmSystemToolsWindowsHandle h = CreateFileW(
- SystemTools::ConvertToWindowsExtendedPath(fname).c_str(), GENERIC_READ,
- FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
- if (!h) {
- return false;
- }
- if (!GetFileTime(h, &t->timeCreation, &t->timeLastAccess,
- &t->timeLastWrite)) {
- return false;
- }
-#else
- struct stat st;
- if (stat(fname, &st) < 0) {
- return false;
- }
- t->timeBuf.actime = st.st_atime;
- t->timeBuf.modtime = st.st_mtime;
-#endif
- return true;
-}
-
-bool cmSystemTools::FileTimeSet(const char* fname, cmSystemToolsFileTime* t)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
- cmSystemToolsWindowsHandle h = CreateFileW(
- SystemTools::ConvertToWindowsExtendedPath(fname).c_str(),
- FILE_WRITE_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
- if (!h) {
- return false;
- }
- return SetFileTime(h, &t->timeCreation, &t->timeLastAccess,
- &t->timeLastWrite) != 0;
-#else
- return utime(fname, &t->timeBuf) >= 0;
-#endif
-}
-
#ifdef _WIN32
# ifndef CRYPT_SILENT
# define CRYPT_SILENT 0x40 /* Not defined by VS 6 version of header. */
@@ -3015,7 +2949,7 @@ bool cmSystemTools::CheckRPath(std::string const& file,
#endif
}
-bool cmSystemTools::RepeatedRemoveDirectory(const char* dir)
+bool cmSystemTools::RepeatedRemoveDirectory(const std::string& dir)
{
// Windows sometimes locks files temporarily so try a few times.
for (int i = 0; i < 10; ++i) {
@@ -3064,6 +2998,12 @@ bool cmSystemTools::StringToULong(const char* str, unsigned long* value)
{
errno = 0;
char* endp;
+ while (isspace(*str)) {
+ ++str;
+ }
+ if (*str == '-') {
+ return false;
+ }
*value = strtoul(str, &endp, 10);
return (*endp == '\0') && (endp != str) && (errno == 0);
}
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 0f92fe257..016c2665f 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -15,8 +15,6 @@
#include <string>
#include <vector>
-class cmSystemToolsFileTime;
-
/** \class cmSystemTools
* \brief A collection of useful functions for CMake.
*
@@ -29,23 +27,56 @@ public:
typedef cmsys::SystemTools Superclass;
typedef cmProcessOutput::Encoding Encoding;
- /** Expand out any arguments in the vector that have ; separated
- * strings into multiple arguments. A new vector is created
- * containing the expanded versions of all arguments in argsIn.
+ /**
+ * Expand the ; separated string @a arg into multiple arguments.
+ * All found arguments are appended to @a argsOut.
*/
- static void ExpandList(std::vector<std::string> const& argsIn,
- std::vector<std::string>& argsOut);
static void ExpandListArgument(const std::string& arg,
std::vector<std::string>& argsOut,
bool emptyArgs = false);
/**
+ * Expand out any arguments in the string range [@a first, @a last) that have
+ * ; separated strings into multiple arguments. All found arguments are
+ * appended to @a argsOut.
+ */
+ template <class InputIt>
+ static void ExpandLists(InputIt first, InputIt last,
+ std::vector<std::string>& argsOut)
+ {
+ for (; first != last; ++first) {
+ cmSystemTools::ExpandListArgument(*first, argsOut);
+ }
+ }
+
+ /**
+ * Same as ExpandListArgument but a new vector is created containing
+ * the expanded arguments from the string @a arg.
+ */
+ static std::vector<std::string> ExpandedListArgument(const std::string& arg,
+ bool emptyArgs = false);
+
+ /**
+ * Same as ExpandList but a new vector is created containing the expanded
+ * versions of all arguments in the string range [@a first, @a last).
+ */
+ template <class InputIt>
+ static std::vector<std::string> ExpandedLists(InputIt first, InputIt last)
+ {
+ std::vector<std::string> argsOut;
+ for (; first != last; ++first) {
+ cmSystemTools::ExpandListArgument(*first, argsOut);
+ }
+ return argsOut;
+ }
+
+ /**
* Look for and replace registry values in a string
*/
static void ExpandRegistryValues(std::string& source,
KeyWOW64 view = KeyWOW64_Default);
- ///! Escape quotes in a string.
+ //! Escape quotes in a string.
static std::string EscapeQuotes(const std::string& str);
/** Map help document name to file name. */
@@ -56,7 +87,7 @@ public:
*/
static std::string TrimWhitespace(const std::string& s);
- using MessageCallback = std::function<void(const char*, const char*)>;
+ using MessageCallback = std::function<void(const std::string&, const char*)>;
/**
* Set the function used by GUIs to display error messages
* Function gets passed: message as a const char*,
@@ -67,26 +98,20 @@ public:
/**
* Display an error message.
*/
- static void Error(const char* m, const char* m2 = nullptr,
- const char* m3 = nullptr, const char* m4 = nullptr);
static void Error(const std::string& m);
/**
* Display a message.
*/
- static void Message(const char* m, const char* title = nullptr);
- static void Message(const std::string& m, const char* title = nullptr)
- {
- Message(m.c_str(), title);
- }
+ static void Message(const std::string& m, const char* title = nullptr);
using OutputCallback = std::function<void(std::string const&)>;
- ///! Send a string to stdout
+ //! Send a string to stdout
static void Stdout(const std::string& s);
static void SetStdoutCallback(OutputCallback f);
- ///! Send a string to stderr
+ //! Send a string to stderr
static void Stderr(const std::string& s);
static void SetStderrCallback(OutputCallback f);
@@ -94,25 +119,25 @@ public:
static void SetInterruptCallback(InterruptCallback f);
static bool GetInterruptFlag();
- ///! Return true if there was an error at any point.
+ //! Return true if there was an error at any point.
static bool GetErrorOccuredFlag()
{
return cmSystemTools::s_ErrorOccured ||
cmSystemTools::s_FatalErrorOccured || GetInterruptFlag();
}
- ///! If this is set to true, cmake stops processing commands.
+ //! If this is set to true, cmake stops processing commands.
static void SetFatalErrorOccured()
{
cmSystemTools::s_FatalErrorOccured = true;
}
static void SetErrorOccured() { cmSystemTools::s_ErrorOccured = true; }
- ///! Return true if there was an error at any point.
+ //! Return true if there was an error at any point.
static bool GetFatalErrorOccured()
{
return cmSystemTools::s_FatalErrorOccured || GetInterruptFlag();
}
- ///! Set the error occurred flag and fatal error back to false
+ //! Set the error occurred flag and fatal error back to false
static void ResetErrorOccuredFlag()
{
cmSystemTools::s_FatalErrorOccured = false;
@@ -142,22 +167,22 @@ public:
static bool IsOff(const char* val);
static bool IsOff(const std::string& val);
- ///! Return true if value is NOTFOUND or ends in -NOTFOUND.
+ //! Return true if value is NOTFOUND or ends in -NOTFOUND.
static bool IsNOTFOUND(const char* value);
- ///! Return true if the path is a framework
- static bool IsPathToFramework(const char* value);
+ //! Return true if the path is a framework
+ static bool IsPathToFramework(const std::string& value);
static bool DoesFileExistWithExtensions(
- const char* name, const std::vector<std::string>& sourceExts);
+ const std::string& name, const std::vector<std::string>& sourceExts);
/**
* Check if the given file exists in one of the parent directory of the
* given file or directory and if it does, return the name of the file.
* Toplevel specifies the top-most directory to where it will look.
*/
- static std::string FileExistsInParentDirectories(const char* fname,
- const char* directory,
- const char* toplevel);
+ static std::string FileExistsInParentDirectories(
+ const std::string& fname, const std::string& directory,
+ const std::string& toplevel);
static void Glob(const std::string& directory, const std::string& regexp,
std::vector<std::string>& files);
@@ -176,23 +201,19 @@ public:
static bool SimpleGlob(const std::string& glob,
std::vector<std::string>& files, int type = 0);
- ///! Copy a file.
- static bool cmCopyFile(const std::string& source,
- const std::string& destination);
-
/** Rename a file or directory within a single disk volume (atomic
if possible). */
static bool RenameFile(const std::string& oldname,
const std::string& newname);
- ///! Compute the hash of a file
+ //! Compute the hash of a file
static std::string ComputeFileHash(const std::string& source,
cmCryptoHash::Algo algo);
/** Compute the md5sum of a string. */
static std::string ComputeStringMD5(const std::string& input);
- ///! Get the SHA thumbprint for a certificate file
+ //! Get the SHA thumbprint for a certificate file
static std::string ComputeCertificateThumbprint(const std::string& source);
/**
@@ -224,7 +245,7 @@ public:
OUTPUT_FORWARD,
OUTPUT_PASSTHROUGH
};
- static bool RunSingleCommand(const char* command,
+ static bool RunSingleCommand(const std::string& command,
std::string* captureStdOut = nullptr,
std::string* captureStdErr = nullptr,
int* retVal = nullptr,
@@ -250,7 +271,7 @@ public:
/**
* Parse arguments out of a single string command
*/
- static std::vector<std::string> ParseArguments(const char* command);
+ static std::vector<std::string> ParseArguments(const std::string& command);
/** Parse arguments out of a windows command line string. */
static void ParseWindowsCommandLine(const char* command,
@@ -274,8 +295,6 @@ public:
static size_t CalculateCommandLineLengthLimit();
- static void EnableMessages() { s_DisableMessages = false; }
- static void DisableMessages() { s_DisableMessages = true; }
static void DisableRunCommandOutput() { s_DisableRunCommandOutput = true; }
static void EnableRunCommandOutput() { s_DisableRunCommandOutput = false; }
static bool GetRunCommandOutput() { return s_DisableRunCommandOutput; }
@@ -351,9 +370,6 @@ public:
cmDuration timeout, std::vector<char>& out,
std::vector<char>& err);
- /** Split a string on its newlines into multiple lines. Returns
- false only if the last line stored had no newline. */
- static bool Split(const char* s, std::vector<std::string>& l);
static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; }
static bool GetForceUnixPaths() { return s_ForceUnixPaths; }
@@ -364,7 +380,7 @@ public:
// ConvertToRunCommandPath does not use s_ForceUnixPaths and should
// be used when RunCommand is called from cmake, because the
// running cmake needs paths to be in its format
- static std::string ConvertToRunCommandPath(const char* path);
+ static std::string ConvertToRunCommandPath(const std::string& path);
/** compute the relative path from local to remote. local must
be a directory. remote can be a file or a directory.
@@ -385,12 +401,6 @@ public:
static std::string ForceToRelativePath(std::string const& local_path,
std::string const& remote_path);
- /** Joins two paths while collapsing x/../ parts
- * For example CollapseCombinedPath("a/b/c", "../../d") results in "a/d"
- */
- static std::string CollapseCombinedPath(std::string const& dir,
- std::string const& file);
-
#ifdef CMAKE_BUILD_WITH_CMAKE
/** Remove an environment variable */
static bool UnsetEnv(const char* value);
@@ -423,21 +433,33 @@ public:
/** Setup the environment to enable VS 8 IDE output. */
static void EnableVSConsoleOutput();
+ enum cmTarAction
+ {
+ TarActionCreate,
+ TarActionList,
+ TarActionExtract,
+ TarActionNone
+ };
+
/** Create tar */
enum cmTarCompression
{
TarCompressGZip,
TarCompressBZip2,
TarCompressXZ,
+ TarCompressZstd,
TarCompressNone
};
- static bool ListTar(const char* outFileName, bool verbose);
- static bool CreateTar(const char* outFileName,
+
+ static bool ListTar(const std::string& outFileName,
+ const std::vector<std::string>& files, bool verbose);
+ static bool CreateTar(const std::string& outFileName,
const std::vector<std::string>& files,
cmTarCompression compressType, bool verbose,
std::string const& mtime = std::string(),
std::string const& format = std::string());
- static bool ExtractTar(const char* inFileName, bool verbose);
+ static bool ExtractTar(const std::string& inFileName,
+ const std::vector<std::string>& files, bool verbose);
// This should be called first thing in main
// it will keep child processes from inheriting the
// stdin and stdout of this process. This is important
@@ -445,15 +467,7 @@ public:
// not get stuck waiting for all the output on the pipes.
static void DoNotInheritStdPipes();
- /** Copy the file create/access/modify times from the file named by
- the first argument to that named by the second. */
- static bool CopyFileTime(const char* fromFile, const char* toFile);
-
- /** Save and restore file times. */
- static cmSystemToolsFileTime* FileTimeNew();
- static void FileTimeDelete(cmSystemToolsFileTime*);
- static bool FileTimeGet(const char* fname, cmSystemToolsFileTime* t);
- static bool FileTimeSet(const char* fname, cmSystemToolsFileTime* t);
+ static void EnsureStdPipes();
/** Random seed generation. */
static unsigned int RandomSeed();
@@ -497,7 +511,7 @@ public:
static bool CheckRPath(std::string const& file, std::string const& newRPath);
/** Remove a directory; repeat a few times in case of locked files. */
- static bool RepeatedRemoveDirectory(const char* dir);
+ static bool RepeatedRemoveDirectory(const std::string& dir);
/** Tokenize a string */
static std::vector<std::string> tokenize(const std::string& str,
@@ -546,7 +560,6 @@ private:
static bool s_RunCommandHideConsole;
static bool s_ErrorOccured;
static bool s_FatalErrorOccured;
- static bool s_DisableMessages;
static bool s_DisableRunCommandOutput;
};
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 93cdd46ce..cd675865a 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -5,6 +5,7 @@
#include "cmsys/RegularExpression.hxx"
#include <algorithm>
#include <assert.h>
+#include <initializer_list>
#include <iterator>
#include <set>
#include <sstream>
@@ -12,6 +13,7 @@
#include <unordered_set>
#include "cmAlgorithms.h"
+#include "cmCustomCommand.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
@@ -20,6 +22,8 @@
#include "cmMessageType.h"
#include "cmMessenger.h"
#include "cmProperty.h"
+#include "cmPropertyMap.h"
+#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmSourceFileLocation.h"
#include "cmSourceFileLocationKind.h"
@@ -155,6 +159,26 @@ const char* cmTargetPropertyComputer::GetSources<cmTarget>(
class cmTargetInternals
{
public:
+ cmStateEnums::TargetType TargetType;
+ cmMakefile* Makefile;
+ cmPolicies::PolicyMap PolicyMap;
+ std::string Name;
+ std::string InstallPath;
+ std::string RuntimeInstallPath;
+ cmPropertyMap Properties;
+ bool IsGeneratorProvided;
+ bool HaveInstallRule;
+ bool DLLPlatform;
+ bool IsAndroid;
+ bool IsImportedTarget;
+ bool ImportedGloballyVisible;
+ bool BuildInterfaceIncludesAppended;
+ std::set<BT<std::string>> Utilities;
+ std::vector<cmCustomCommand> PreBuildCommands;
+ std::vector<cmCustomCommand> PreLinkCommands;
+ std::vector<cmCustomCommand> PostBuildCommands;
+ std::set<std::string> SystemIncludeDirectories;
+ cmTarget::LinkLibraryVectorType OriginalLinkLibraries;
std::vector<std::string> IncludeDirectoriesEntries;
std::vector<cmListFileBacktrace> IncludeDirectoriesBacktraces;
std::vector<std::string> CompileOptionsEntries;
@@ -171,166 +195,188 @@ public:
std::vector<cmListFileBacktrace> LinkDirectoriesBacktraces;
std::vector<std::string> LinkImplementationPropertyEntries;
std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces;
+ std::vector<std::pair<cmTarget::TLLSignature, cmListFileContext>>
+ TLLCommands;
+ cmListFileBacktrace Backtrace;
+
+public:
+ bool CheckImportedLibName(std::string const& prop,
+ std::string const& value) const;
+
+ std::string ProcessSourceItemCMP0049(const std::string& s);
};
cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
Visibility vis, cmMakefile* mf)
+ : impl(cm::make_unique<cmTargetInternals>())
{
assert(mf);
- this->IsGeneratorProvided = false;
- this->Name = name;
- this->TargetTypeValue = type;
- this->Makefile = mf;
- this->HaveInstallRule = false;
- this->DLLPlatform = false;
- this->IsAndroid = false;
- this->IsImportedTarget =
+ impl->TargetType = type;
+ impl->Makefile = mf;
+ impl->Name = name;
+ impl->IsGeneratorProvided = false;
+ impl->HaveInstallRule = false;
+ impl->DLLPlatform = false;
+ impl->IsAndroid = false;
+ impl->IsImportedTarget =
(vis == VisibilityImported || vis == VisibilityImportedGlobally);
- this->ImportedGloballyVisible = vis == VisibilityImportedGlobally;
- this->BuildInterfaceIncludesAppended = false;
+ impl->ImportedGloballyVisible = vis == VisibilityImportedGlobally;
+ impl->BuildInterfaceIncludesAppended = false;
// Check whether this is a DLL platform.
- this->DLLPlatform =
- !this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
+ impl->DLLPlatform =
+ !impl->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
// Check whether we are targeting an Android platform.
- this->IsAndroid =
- (this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android");
+ impl->IsAndroid =
+ (impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android");
+
+ std::string gKey;
+ gKey.reserve(128);
+ gKey += "CMAKE_";
+ auto InitProperty = [this, mf, &gKey](const std::string& property,
+ const char* default_value) {
+ // Replace everything after "CMAKE_"
+ gKey.replace(gKey.begin() + 6, gKey.end(), property);
+ if (const char* value = mf->GetDefinition(gKey)) {
+ this->SetProperty(property, value);
+ } else if (default_value) {
+ this->SetProperty(property, default_value);
+ }
+ };
// Setup default property values.
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
this->GetType() != cmStateEnums::UTILITY) {
- this->SetPropertyDefault("ANDROID_API", nullptr);
- this->SetPropertyDefault("ANDROID_API_MIN", nullptr);
- this->SetPropertyDefault("ANDROID_ARCH", nullptr);
- this->SetPropertyDefault("ANDROID_STL_TYPE", nullptr);
- this->SetPropertyDefault("ANDROID_SKIP_ANT_STEP", nullptr);
- this->SetPropertyDefault("ANDROID_PROCESS_MAX", nullptr);
- this->SetPropertyDefault("ANDROID_PROGUARD", nullptr);
- this->SetPropertyDefault("ANDROID_PROGUARD_CONFIG_PATH", nullptr);
- this->SetPropertyDefault("ANDROID_SECURE_PROPS_PATH", nullptr);
- this->SetPropertyDefault("ANDROID_NATIVE_LIB_DIRECTORIES", nullptr);
- this->SetPropertyDefault("ANDROID_NATIVE_LIB_DEPENDENCIES", nullptr);
- this->SetPropertyDefault("ANDROID_JAVA_SOURCE_DIR", nullptr);
- this->SetPropertyDefault("ANDROID_JAR_DIRECTORIES", nullptr);
- this->SetPropertyDefault("ANDROID_JAR_DEPENDENCIES", nullptr);
- this->SetPropertyDefault("ANDROID_ASSETS_DIRECTORIES", nullptr);
- this->SetPropertyDefault("ANDROID_ANT_ADDITIONAL_OPTIONS", nullptr);
- this->SetPropertyDefault("BUILD_RPATH", nullptr);
- this->SetPropertyDefault("BUILD_RPATH_USE_ORIGIN", nullptr);
- this->SetPropertyDefault("INSTALL_NAME_DIR", nullptr);
- this->SetPropertyDefault("INSTALL_RPATH", "");
- this->SetPropertyDefault("INSTALL_RPATH_USE_LINK_PATH", "OFF");
- this->SetPropertyDefault("INTERPROCEDURAL_OPTIMIZATION", nullptr);
- this->SetPropertyDefault("SKIP_BUILD_RPATH", "OFF");
- this->SetPropertyDefault("BUILD_WITH_INSTALL_RPATH", "OFF");
- this->SetPropertyDefault("ARCHIVE_OUTPUT_DIRECTORY", nullptr);
- this->SetPropertyDefault("LIBRARY_OUTPUT_DIRECTORY", nullptr);
- this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", nullptr);
- this->SetPropertyDefault("PDB_OUTPUT_DIRECTORY", nullptr);
- this->SetPropertyDefault("COMPILE_PDB_OUTPUT_DIRECTORY", nullptr);
- this->SetPropertyDefault("Fortran_FORMAT", nullptr);
- this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", nullptr);
- this->SetPropertyDefault("Fortran_COMPILER_LAUNCHER", nullptr);
- this->SetPropertyDefault("GNUtoMS", nullptr);
- this->SetPropertyDefault("OSX_ARCHITECTURES", nullptr);
- this->SetPropertyDefault("IOS_INSTALL_COMBINED", nullptr);
- this->SetPropertyDefault("AUTOMOC", nullptr);
- this->SetPropertyDefault("AUTOUIC", nullptr);
- this->SetPropertyDefault("AUTORCC", nullptr);
- this->SetPropertyDefault("AUTOGEN_ORIGIN_DEPENDS", nullptr);
- this->SetPropertyDefault("AUTOGEN_PARALLEL", nullptr);
- this->SetPropertyDefault("AUTOMOC_COMPILER_PREDEFINES", nullptr);
- this->SetPropertyDefault("AUTOMOC_DEPEND_FILTERS", nullptr);
- this->SetPropertyDefault("AUTOMOC_MACRO_NAMES", nullptr);
- this->SetPropertyDefault("AUTOMOC_MOC_OPTIONS", nullptr);
- this->SetPropertyDefault("AUTOUIC_OPTIONS", nullptr);
- this->SetPropertyDefault("AUTOUIC_SEARCH_PATHS", nullptr);
- this->SetPropertyDefault("AUTORCC_OPTIONS", nullptr);
- this->SetPropertyDefault("LINK_DEPENDS_NO_SHARED", nullptr);
- this->SetPropertyDefault("LINK_INTERFACE_LIBRARIES", nullptr);
- this->SetPropertyDefault("WIN32_EXECUTABLE", nullptr);
- this->SetPropertyDefault("MACOSX_BUNDLE", nullptr);
- this->SetPropertyDefault("MACOSX_RPATH", nullptr);
- this->SetPropertyDefault("NO_SYSTEM_FROM_IMPORTED", nullptr);
- this->SetPropertyDefault("BUILD_WITH_INSTALL_NAME_DIR", nullptr);
- this->SetPropertyDefault("C_CLANG_TIDY", nullptr);
- this->SetPropertyDefault("C_COMPILER_LAUNCHER", nullptr);
- this->SetPropertyDefault("C_CPPLINT", nullptr);
- this->SetPropertyDefault("C_CPPCHECK", nullptr);
- this->SetPropertyDefault("C_INCLUDE_WHAT_YOU_USE", nullptr);
- this->SetPropertyDefault("LINK_WHAT_YOU_USE", nullptr);
- this->SetPropertyDefault("C_STANDARD", nullptr);
- this->SetPropertyDefault("C_STANDARD_REQUIRED", nullptr);
- this->SetPropertyDefault("C_EXTENSIONS", nullptr);
- this->SetPropertyDefault("CXX_CLANG_TIDY", nullptr);
- this->SetPropertyDefault("CXX_COMPILER_LAUNCHER", nullptr);
- this->SetPropertyDefault("CXX_CPPLINT", nullptr);
- this->SetPropertyDefault("CXX_CPPCHECK", nullptr);
- this->SetPropertyDefault("CXX_INCLUDE_WHAT_YOU_USE", nullptr);
- this->SetPropertyDefault("CXX_STANDARD", nullptr);
- this->SetPropertyDefault("CXX_STANDARD_REQUIRED", nullptr);
- this->SetPropertyDefault("CXX_EXTENSIONS", nullptr);
- this->SetPropertyDefault("CUDA_STANDARD", nullptr);
- this->SetPropertyDefault("CUDA_STANDARD_REQUIRED", nullptr);
- this->SetPropertyDefault("CUDA_EXTENSIONS", nullptr);
- this->SetPropertyDefault("CUDA_COMPILER_LAUNCHER", nullptr);
- this->SetPropertyDefault("CUDA_SEPARABLE_COMPILATION", nullptr);
- this->SetPropertyDefault("LINK_SEARCH_START_STATIC", nullptr);
- this->SetPropertyDefault("LINK_SEARCH_END_STATIC", nullptr);
- this->SetPropertyDefault("FOLDER", nullptr);
+ InitProperty("ANDROID_API", nullptr);
+ InitProperty("ANDROID_API_MIN", nullptr);
+ InitProperty("ANDROID_ARCH", nullptr);
+ InitProperty("ANDROID_STL_TYPE", nullptr);
+ InitProperty("ANDROID_SKIP_ANT_STEP", nullptr);
+ InitProperty("ANDROID_PROCESS_MAX", nullptr);
+ InitProperty("ANDROID_PROGUARD", nullptr);
+ InitProperty("ANDROID_PROGUARD_CONFIG_PATH", nullptr);
+ InitProperty("ANDROID_SECURE_PROPS_PATH", nullptr);
+ InitProperty("ANDROID_NATIVE_LIB_DIRECTORIES", nullptr);
+ InitProperty("ANDROID_NATIVE_LIB_DEPENDENCIES", nullptr);
+ InitProperty("ANDROID_JAVA_SOURCE_DIR", nullptr);
+ InitProperty("ANDROID_JAR_DIRECTORIES", nullptr);
+ InitProperty("ANDROID_JAR_DEPENDENCIES", nullptr);
+ InitProperty("ANDROID_ASSETS_DIRECTORIES", nullptr);
+ InitProperty("ANDROID_ANT_ADDITIONAL_OPTIONS", nullptr);
+ InitProperty("BUILD_RPATH", nullptr);
+ InitProperty("BUILD_RPATH_USE_ORIGIN", nullptr);
+ InitProperty("INSTALL_NAME_DIR", nullptr);
+ InitProperty("INSTALL_RPATH", "");
+ InitProperty("INSTALL_RPATH_USE_LINK_PATH", "OFF");
+ InitProperty("INTERPROCEDURAL_OPTIMIZATION", nullptr);
+ InitProperty("SKIP_BUILD_RPATH", "OFF");
+ InitProperty("BUILD_WITH_INSTALL_RPATH", "OFF");
+ InitProperty("ARCHIVE_OUTPUT_DIRECTORY", nullptr);
+ InitProperty("LIBRARY_OUTPUT_DIRECTORY", nullptr);
+ InitProperty("RUNTIME_OUTPUT_DIRECTORY", nullptr);
+ InitProperty("PDB_OUTPUT_DIRECTORY", nullptr);
+ InitProperty("COMPILE_PDB_OUTPUT_DIRECTORY", nullptr);
+ InitProperty("FRAMEWORK", nullptr);
+ InitProperty("Fortran_FORMAT", nullptr);
+ InitProperty("Fortran_MODULE_DIRECTORY", nullptr);
+ InitProperty("Fortran_COMPILER_LAUNCHER", nullptr);
+ InitProperty("GNUtoMS", nullptr);
+ InitProperty("OSX_ARCHITECTURES", nullptr);
+ InitProperty("IOS_INSTALL_COMBINED", nullptr);
+ InitProperty("AUTOMOC", nullptr);
+ InitProperty("AUTOUIC", nullptr);
+ InitProperty("AUTORCC", nullptr);
+ InitProperty("AUTOGEN_ORIGIN_DEPENDS", nullptr);
+ InitProperty("AUTOGEN_PARALLEL", nullptr);
+ InitProperty("AUTOMOC_COMPILER_PREDEFINES", nullptr);
+ InitProperty("AUTOMOC_DEPEND_FILTERS", nullptr);
+ InitProperty("AUTOMOC_MACRO_NAMES", nullptr);
+ InitProperty("AUTOMOC_MOC_OPTIONS", nullptr);
+ InitProperty("AUTOUIC_OPTIONS", nullptr);
+ InitProperty("AUTOUIC_SEARCH_PATHS", nullptr);
+ InitProperty("AUTORCC_OPTIONS", nullptr);
+ InitProperty("LINK_DEPENDS_NO_SHARED", nullptr);
+ InitProperty("LINK_INTERFACE_LIBRARIES", nullptr);
+ InitProperty("MSVC_RUNTIME_LIBRARY", nullptr);
+ InitProperty("WIN32_EXECUTABLE", nullptr);
+ InitProperty("MACOSX_BUNDLE", nullptr);
+ InitProperty("MACOSX_RPATH", nullptr);
+ InitProperty("NO_SYSTEM_FROM_IMPORTED", nullptr);
+ InitProperty("BUILD_WITH_INSTALL_NAME_DIR", nullptr);
+ InitProperty("C_CLANG_TIDY", nullptr);
+ InitProperty("C_COMPILER_LAUNCHER", nullptr);
+ InitProperty("C_CPPLINT", nullptr);
+ InitProperty("C_CPPCHECK", nullptr);
+ InitProperty("C_INCLUDE_WHAT_YOU_USE", nullptr);
+ InitProperty("LINK_WHAT_YOU_USE", nullptr);
+ InitProperty("C_STANDARD", nullptr);
+ InitProperty("C_STANDARD_REQUIRED", nullptr);
+ InitProperty("C_EXTENSIONS", nullptr);
+ InitProperty("CXX_CLANG_TIDY", nullptr);
+ InitProperty("CXX_COMPILER_LAUNCHER", nullptr);
+ InitProperty("CXX_CPPLINT", nullptr);
+ InitProperty("CXX_CPPCHECK", nullptr);
+ InitProperty("CXX_INCLUDE_WHAT_YOU_USE", nullptr);
+ InitProperty("CXX_STANDARD", nullptr);
+ InitProperty("CXX_STANDARD_REQUIRED", nullptr);
+ InitProperty("CXX_EXTENSIONS", nullptr);
+ InitProperty("CUDA_STANDARD", nullptr);
+ InitProperty("CUDA_STANDARD_REQUIRED", nullptr);
+ InitProperty("CUDA_EXTENSIONS", nullptr);
+ InitProperty("CUDA_COMPILER_LAUNCHER", nullptr);
+ InitProperty("CUDA_SEPARABLE_COMPILATION", nullptr);
+ InitProperty("LINK_SEARCH_START_STATIC", nullptr);
+ InitProperty("LINK_SEARCH_END_STATIC", nullptr);
+ InitProperty("FOLDER", nullptr);
+ InitProperty("Swift_MODULE_DIRECTORY", nullptr);
+ InitProperty("VS_JUST_MY_CODE_DEBUGGING", nullptr);
#ifdef __APPLE__
if (this->GetGlobalGenerator()->IsXcode()) {
- this->SetPropertyDefault("XCODE_SCHEME_ADDRESS_SANITIZER", nullptr);
- this->SetPropertyDefault(
- "XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_THREAD_SANITIZER", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_THREAD_SANITIZER_STOP", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER",
- nullptr);
- this->SetPropertyDefault(
- "XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER",
- nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP",
- nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_MALLOC_SCRIBBLE", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_MALLOC_GUARD_EDGES", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_GUARD_MALLOC", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_ZOMBIE_OBJECTS", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_MALLOC_STACK", nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE",
- nullptr);
- this->SetPropertyDefault("XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS", nullptr);
+ InitProperty("XCODE_GENERATE_SCHEME", nullptr);
+ InitProperty("XCODE_SCHEME_ADDRESS_SANITIZER", nullptr);
+ InitProperty("XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN", nullptr);
+ InitProperty("XCODE_SCHEME_THREAD_SANITIZER", nullptr);
+ InitProperty("XCODE_SCHEME_THREAD_SANITIZER_STOP", nullptr);
+ InitProperty("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER", nullptr);
+ InitProperty("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP", nullptr);
+ InitProperty("XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER", nullptr);
+ InitProperty("XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP", nullptr);
+ InitProperty("XCODE_SCHEME_MALLOC_SCRIBBLE", nullptr);
+ InitProperty("XCODE_SCHEME_MALLOC_GUARD_EDGES", nullptr);
+ InitProperty("XCODE_SCHEME_GUARD_MALLOC", nullptr);
+ InitProperty("XCODE_SCHEME_ZOMBIE_OBJECTS", nullptr);
+ InitProperty("XCODE_SCHEME_MALLOC_STACK", nullptr);
+ InitProperty("XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE", nullptr);
+ InitProperty("XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS", nullptr);
}
#endif
}
- // Collect the set of configuration types.
- std::vector<std::string> configNames;
- mf->GetConfigurations(configNames);
-
// Setup per-configuration property default values.
if (this->GetType() != cmStateEnums::UTILITY) {
- const char* configProps[] = {
+ static const auto configProps = {
/* clang-format needs this comment to break after the opening brace */
"ARCHIVE_OUTPUT_DIRECTORY_", "LIBRARY_OUTPUT_DIRECTORY_",
"RUNTIME_OUTPUT_DIRECTORY_", "PDB_OUTPUT_DIRECTORY_",
"COMPILE_PDB_OUTPUT_DIRECTORY_", "MAP_IMPORTED_CONFIG_",
- "INTERPROCEDURAL_OPTIMIZATION_", nullptr
+ "INTERPROCEDURAL_OPTIMIZATION_"
};
+ // Collect the set of configuration types.
+ std::vector<std::string> configNames;
+ mf->GetConfigurations(configNames);
for (std::string const& configName : configNames) {
std::string configUpper = cmSystemTools::UpperCase(configName);
- for (const char** p = configProps; *p; ++p) {
+ for (auto const& prop : configProps) {
// Interface libraries have no output locations, so honor only
// the configuration map.
- if (this->TargetTypeValue == cmStateEnums::INTERFACE_LIBRARY &&
- strcmp(*p, "MAP_IMPORTED_CONFIG_") != 0) {
+ if (impl->TargetType == cmStateEnums::INTERFACE_LIBRARY &&
+ strcmp(prop, "MAP_IMPORTED_CONFIG_") != 0) {
continue;
}
- std::string property = *p;
+ std::string property = prop;
property += configUpper;
- this->SetPropertyDefault(property, nullptr);
+ InitProperty(property, nullptr);
}
// Initialize per-configuration name postfix property from the
@@ -338,122 +384,93 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
// compatibility with previous CMake versions in which executables
// did not support this variable. Projects may still specify the
// property directly.
- if (this->TargetTypeValue != cmStateEnums::EXECUTABLE &&
- this->TargetTypeValue != cmStateEnums::INTERFACE_LIBRARY) {
+ if (impl->TargetType != cmStateEnums::EXECUTABLE &&
+ impl->TargetType != cmStateEnums::INTERFACE_LIBRARY) {
std::string property = cmSystemTools::UpperCase(configName);
property += "_POSTFIX";
- this->SetPropertyDefault(property, nullptr);
+ InitProperty(property, nullptr);
}
}
}
// Save the backtrace of target construction.
- this->Backtrace = this->Makefile->GetBacktrace();
+ impl->Backtrace = impl->Makefile->GetBacktrace();
if (!this->IsImported()) {
// Initialize the INCLUDE_DIRECTORIES property based on the current value
// of the same directory property:
- const cmStringRange parentIncludes =
- this->Makefile->GetIncludeDirectoriesEntries();
- const cmBacktraceRange parentIncludesBts =
- this->Makefile->GetIncludeDirectoriesBacktraces();
-
- this->Internal->IncludeDirectoriesEntries.insert(
- this->Internal->IncludeDirectoriesEntries.end(), parentIncludes.begin(),
- parentIncludes.end());
- this->Internal->IncludeDirectoriesBacktraces.insert(
- this->Internal->IncludeDirectoriesBacktraces.end(),
- parentIncludesBts.begin(), parentIncludesBts.end());
-
- const std::set<std::string> parentSystemIncludes =
- this->Makefile->GetSystemIncludeDirectories();
-
- this->SystemIncludeDirectories.insert(parentSystemIncludes.begin(),
- parentSystemIncludes.end());
-
- const cmStringRange parentCompileOptions =
- this->Makefile->GetCompileOptionsEntries();
- const cmBacktraceRange parentCompileOptionsBts =
- this->Makefile->GetCompileOptionsBacktraces();
-
- this->Internal->CompileOptionsEntries.insert(
- this->Internal->CompileOptionsEntries.end(),
- parentCompileOptions.begin(), parentCompileOptions.end());
- this->Internal->CompileOptionsBacktraces.insert(
- this->Internal->CompileOptionsBacktraces.end(),
- parentCompileOptionsBts.begin(), parentCompileOptionsBts.end());
-
- const cmStringRange parentLinkOptions =
- this->Makefile->GetLinkOptionsEntries();
- const cmBacktraceRange parentLinkOptionsBts =
- this->Makefile->GetLinkOptionsBacktraces();
-
- this->Internal->LinkOptionsEntries.insert(
- this->Internal->LinkOptionsEntries.end(), parentLinkOptions.begin(),
- parentLinkOptions.end());
- this->Internal->LinkOptionsBacktraces.insert(
- this->Internal->LinkOptionsBacktraces.end(),
- parentLinkOptionsBts.begin(), parentLinkOptionsBts.end());
-
- const cmStringRange parentLinkDirectories =
- this->Makefile->GetLinkDirectoriesEntries();
- const cmBacktraceRange parentLinkDirectoriesBts =
- this->Makefile->GetLinkDirectoriesBacktraces();
-
- this->Internal->LinkDirectoriesEntries.insert(
- this->Internal->LinkDirectoriesEntries.end(),
- parentLinkDirectories.begin(), parentLinkDirectories.end());
- this->Internal->LinkDirectoriesBacktraces.insert(
- this->Internal->LinkDirectoriesBacktraces.end(),
- parentLinkDirectoriesBts.begin(), parentLinkDirectoriesBts.end());
+ cmAppend(impl->IncludeDirectoriesEntries,
+ impl->Makefile->GetIncludeDirectoriesEntries());
+ cmAppend(impl->IncludeDirectoriesBacktraces,
+ impl->Makefile->GetIncludeDirectoriesBacktraces());
+
+ {
+ auto const& sysInc = impl->Makefile->GetSystemIncludeDirectories();
+ impl->SystemIncludeDirectories.insert(sysInc.begin(), sysInc.end());
+ }
+
+ cmAppend(impl->CompileOptionsEntries,
+ impl->Makefile->GetCompileOptionsEntries());
+ cmAppend(impl->CompileOptionsBacktraces,
+ impl->Makefile->GetCompileOptionsBacktraces());
+
+ cmAppend(impl->LinkOptionsEntries,
+ impl->Makefile->GetLinkOptionsEntries());
+ cmAppend(impl->LinkOptionsBacktraces,
+ impl->Makefile->GetLinkOptionsBacktraces());
+
+ cmAppend(impl->LinkDirectoriesEntries,
+ impl->Makefile->GetLinkDirectoriesEntries());
+ cmAppend(impl->LinkDirectoriesBacktraces,
+ impl->Makefile->GetLinkDirectoriesBacktraces());
}
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
this->GetType() != cmStateEnums::UTILITY) {
- this->SetPropertyDefault("C_VISIBILITY_PRESET", nullptr);
- this->SetPropertyDefault("CXX_VISIBILITY_PRESET", nullptr);
- this->SetPropertyDefault("CUDA_VISIBILITY_PRESET", nullptr);
- this->SetPropertyDefault("VISIBILITY_INLINES_HIDDEN", nullptr);
+ InitProperty("C_VISIBILITY_PRESET", nullptr);
+ InitProperty("CXX_VISIBILITY_PRESET", nullptr);
+ InitProperty("CUDA_VISIBILITY_PRESET", nullptr);
+ InitProperty("VISIBILITY_INLINES_HIDDEN", nullptr);
}
- if (this->TargetTypeValue == cmStateEnums::EXECUTABLE) {
- this->SetPropertyDefault("ANDROID_GUI", nullptr);
- this->SetPropertyDefault("CROSSCOMPILING_EMULATOR", nullptr);
- this->SetPropertyDefault("ENABLE_EXPORTS", nullptr);
+ if (impl->TargetType == cmStateEnums::EXECUTABLE) {
+ InitProperty("ANDROID_GUI", nullptr);
+ InitProperty("CROSSCOMPILING_EMULATOR", nullptr);
+ InitProperty("ENABLE_EXPORTS", nullptr);
}
- if (this->TargetTypeValue == cmStateEnums::SHARED_LIBRARY ||
- this->TargetTypeValue == cmStateEnums::MODULE_LIBRARY) {
+ if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
+ impl->TargetType == cmStateEnums::MODULE_LIBRARY) {
this->SetProperty("POSITION_INDEPENDENT_CODE", "True");
}
- if (this->TargetTypeValue == cmStateEnums::SHARED_LIBRARY ||
- this->TargetTypeValue == cmStateEnums::EXECUTABLE) {
- this->SetPropertyDefault("WINDOWS_EXPORT_ALL_SYMBOLS", nullptr);
+ if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
+ impl->TargetType == cmStateEnums::EXECUTABLE) {
+ InitProperty("WINDOWS_EXPORT_ALL_SYMBOLS", nullptr);
}
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
this->GetType() != cmStateEnums::UTILITY) {
- this->SetPropertyDefault("POSITION_INDEPENDENT_CODE", nullptr);
+ InitProperty("POSITION_INDEPENDENT_CODE", nullptr);
}
// Record current policies for later use.
- this->Makefile->RecordPolicies(this->PolicyMap);
+ impl->Makefile->RecordPolicies(impl->PolicyMap);
- if (this->TargetTypeValue == cmStateEnums::INTERFACE_LIBRARY) {
+ if (impl->TargetType == cmStateEnums::INTERFACE_LIBRARY) {
// This policy is checked in a few conditions. The properties relevant
// to the policy are always ignored for cmStateEnums::INTERFACE_LIBRARY
// targets,
// so ensure that the conditions don't lead to nonsense.
- this->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
+ impl->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
}
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
this->GetType() != cmStateEnums::UTILITY) {
- this->SetPropertyDefault("JOB_POOL_COMPILE", nullptr);
- this->SetPropertyDefault("JOB_POOL_LINK", nullptr);
+ InitProperty("JOB_POOL_COMPILE", nullptr);
+ InitProperty("JOB_POOL_LINK", nullptr);
}
- if (this->TargetTypeValue <= cmStateEnums::UTILITY) {
- this->SetPropertyDefault("DOTNET_TARGET_FRAMEWORK_VERSION", nullptr);
+ if (impl->TargetType <= cmStateEnums::UTILITY) {
+ InitProperty("DOTNET_TARGET_FRAMEWORK_VERSION", nullptr);
}
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
@@ -474,7 +491,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
if (assignment != std::string::npos) {
const std::string propName = vsGlobal + i.substr(0, assignment);
const std::string propValue = i.substr(assignment + 1);
- this->SetPropertyDefault(propName, propValue.c_str());
+ InitProperty(propName, propValue.c_str());
}
}
}
@@ -482,20 +499,56 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
}
}
+cmTarget::cmTarget(cmTarget&&) noexcept = default;
+cmTarget::~cmTarget() = default;
+
+cmTarget& cmTarget::operator=(cmTarget&&) noexcept = default;
+
+cmStateEnums::TargetType cmTarget::GetType() const
+{
+ return impl->TargetType;
+}
+
+cmMakefile* cmTarget::GetMakefile() const
+{
+ return impl->Makefile;
+}
+
+cmPolicies::PolicyMap const& cmTarget::GetPolicyMap() const
+{
+ return impl->PolicyMap;
+}
+
+const std::string& cmTarget::GetName() const
+{
+ return impl->Name;
+}
+
+cmPolicies::PolicyStatus cmTarget::GetPolicyStatus(
+ cmPolicies::PolicyID policy) const
+{
+ return impl->PolicyMap.Get(policy);
+}
+
cmGlobalGenerator* cmTarget::GetGlobalGenerator() const
{
- return this->GetMakefile()->GetGlobalGenerator();
+ return impl->Makefile->GetGlobalGenerator();
+}
+
+void cmTarget::AddUtility(std::string const& name, cmMakefile* mf)
+{
+ impl->Utilities.insert(
+ BT<std::string>(name, mf ? mf->GetBacktrace() : cmListFileBacktrace()));
}
-void cmTarget::AddUtility(std::string const& u, cmMakefile* mf)
+std::set<BT<std::string>> const& cmTarget::GetUtilities() const
{
- BT<std::string> util(u, mf ? mf->GetBacktrace() : cmListFileBacktrace());
- this->Utilities.insert(util);
+ return impl->Utilities;
}
cmListFileBacktrace const& cmTarget::GetBacktrace() const
{
- return this->Backtrace;
+ return impl->Backtrace;
}
bool cmTarget::IsExecutableWithExports() const
@@ -504,34 +557,57 @@ bool cmTarget::IsExecutableWithExports() const
this->GetPropertyAsBool("ENABLE_EXPORTS"));
}
-bool cmTarget::HasImportLibrary() const
-{
- return (this->DLLPlatform &&
- (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
- this->IsExecutableWithExports()));
-}
-
bool cmTarget::IsFrameworkOnApple() const
{
return ((this->GetType() == cmStateEnums::SHARED_LIBRARY ||
this->GetType() == cmStateEnums::STATIC_LIBRARY) &&
- this->Makefile->IsOn("APPLE") &&
+ impl->Makefile->IsOn("APPLE") &&
this->GetPropertyAsBool("FRAMEWORK"));
}
bool cmTarget::IsAppBundleOnApple() const
{
return (this->GetType() == cmStateEnums::EXECUTABLE &&
- this->Makefile->IsOn("APPLE") &&
+ impl->Makefile->IsOn("APPLE") &&
this->GetPropertyAsBool("MACOSX_BUNDLE"));
}
+std::vector<cmCustomCommand> const& cmTarget::GetPreBuildCommands() const
+{
+ return impl->PreBuildCommands;
+}
+
+void cmTarget::AddPreBuildCommand(cmCustomCommand const& cmd)
+{
+ impl->PreBuildCommands.push_back(cmd);
+}
+
+std::vector<cmCustomCommand> const& cmTarget::GetPreLinkCommands() const
+{
+ return impl->PreLinkCommands;
+}
+
+void cmTarget::AddPreLinkCommand(cmCustomCommand const& cmd)
+{
+ impl->PreLinkCommands.push_back(cmd);
+}
+
+std::vector<cmCustomCommand> const& cmTarget::GetPostBuildCommands() const
+{
+ return impl->PostBuildCommands;
+}
+
+void cmTarget::AddPostBuildCommand(cmCustomCommand const& cmd)
+{
+ impl->PostBuildCommands.push_back(cmd);
+}
+
void cmTarget::AddTracedSources(std::vector<std::string> const& srcs)
{
if (!srcs.empty()) {
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->SourceEntries.push_back(cmJoin(srcs, ";"));
- this->Internal->SourceBacktraces.push_back(lfbt);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->SourceEntries.push_back(cmJoin(srcs, ";"));
+ impl->SourceBacktraces.push_back(lfbt);
}
}
@@ -542,25 +618,25 @@ void cmTarget::AddSources(std::vector<std::string> const& srcs)
for (auto filename : srcs) {
if (!cmGeneratorExpression::StartsWithGeneratorExpression(filename)) {
if (!filename.empty()) {
- filename = this->ProcessSourceItemCMP0049(filename);
+ filename = impl->ProcessSourceItemCMP0049(filename);
if (filename.empty()) {
return;
}
}
- this->Makefile->GetOrCreateSource(filename);
+ impl->Makefile->GetOrCreateSource(filename);
}
srcFiles += sep;
srcFiles += filename;
sep = ";";
}
if (!srcFiles.empty()) {
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->SourceEntries.push_back(std::move(srcFiles));
- this->Internal->SourceBacktraces.push_back(lfbt);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->SourceEntries.push_back(std::move(srcFiles));
+ impl->SourceBacktraces.push_back(lfbt);
}
}
-std::string cmTarget::ProcessSourceItemCMP0049(const std::string& s)
+std::string cmTargetInternals::ProcessSourceItemCMP0049(const std::string& s)
{
std::string src = s;
@@ -585,7 +661,7 @@ std::string cmTarget::ProcessSourceItemCMP0049(const std::string& s)
}
if (!noMessage) {
e << "Legacy variable expansion in source file \"" << s
- << "\" expanded to \"" << src << "\" in target \"" << this->GetName()
+ << "\" expanded to \"" << src << "\" in target \"" << this->Name
<< "\". This behavior will be removed in a "
"future version of CMake.";
this->Makefile->IssueMessage(messageType, e.str());
@@ -599,7 +675,7 @@ std::string cmTarget::ProcessSourceItemCMP0049(const std::string& s)
cmSourceFile* cmTarget::AddSourceCMP0049(const std::string& s)
{
- std::string src = this->ProcessSourceItemCMP0049(s);
+ std::string src = impl->ProcessSourceItemCMP0049(s);
if (!s.empty() && src.empty()) {
return nullptr;
}
@@ -663,26 +739,22 @@ public:
cmSourceFile* cmTarget::AddSource(const std::string& src, bool before)
{
- cmSourceFileLocation sfl(this->Makefile, src,
+ cmSourceFileLocation sfl(impl->Makefile, src,
cmSourceFileLocationKind::Known);
- if (std::find_if(this->Internal->SourceEntries.begin(),
- this->Internal->SourceEntries.end(),
+ if (std::find_if(impl->SourceEntries.begin(), impl->SourceEntries.end(),
TargetPropertyEntryFinder(sfl)) ==
- this->Internal->SourceEntries.end()) {
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->SourceEntries.insert(
- before ? this->Internal->SourceEntries.begin()
- : this->Internal->SourceEntries.end(),
- src);
- this->Internal->SourceBacktraces.insert(
- before ? this->Internal->SourceBacktraces.begin()
- : this->Internal->SourceBacktraces.end(),
- lfbt);
+ impl->SourceEntries.end()) {
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->SourceEntries.insert(
+ before ? impl->SourceEntries.begin() : impl->SourceEntries.end(), src);
+ impl->SourceBacktraces.insert(before ? impl->SourceBacktraces.begin()
+ : impl->SourceBacktraces.end(),
+ lfbt);
}
if (cmGeneratorExpression::Find(src) != std::string::npos) {
return nullptr;
}
- return this->Makefile->GetOrCreateSource(src, false,
+ return impl->Makefile->GetOrCreateSource(src, false,
cmSourceFileLocationKind::Known);
}
@@ -702,15 +774,13 @@ std::string cmTarget::GetDebugGeneratorExpressions(
// Get the list of configurations considered to be DEBUG.
std::vector<std::string> debugConfigs =
- this->Makefile->GetCMakeInstance()->GetDebugConfigs();
+ impl->Makefile->GetCMakeInstance()->GetDebugConfigs();
std::string configString = "$<CONFIG:" + debugConfigs[0] + ">";
if (debugConfigs.size() > 1) {
- for (std::vector<std::string>::const_iterator li =
- debugConfigs.begin() + 1;
- li != debugConfigs.end(); ++li) {
- configString += ",$<CONFIG:" + *li + ">";
+ for (std::string const& conf : cmMakeRange(debugConfigs).advance(1)) {
+ configString += ",$<CONFIG:" + conf + ">";
}
configString = "$<OR:" + configString + ">";
}
@@ -730,13 +800,13 @@ bool cmTarget::PushTLLCommandTrace(TLLSignature signature,
cmListFileContext const& lfc)
{
bool ret = true;
- if (!this->TLLCommands.empty()) {
- if (this->TLLCommands.back().first != signature) {
+ if (!impl->TLLCommands.empty()) {
+ if (impl->TLLCommands.back().first != signature) {
ret = false;
}
}
- if (this->TLLCommands.empty() || this->TLLCommands.back().second != lfc) {
- this->TLLCommands.emplace_back(signature, lfc);
+ if (impl->TLLCommands.empty() || impl->TLLCommands.back().second != lfc) {
+ impl->TLLCommands.emplace_back(signature, lfc);
}
return ret;
}
@@ -746,18 +816,63 @@ void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const
const char* sigString =
(sig == cmTarget::KeywordTLLSignature ? "keyword" : "plain");
s << "The uses of the " << sigString << " signature are here:\n";
- cmStateDirectory cmDir =
- this->GetMakefile()->GetStateSnapshot().GetDirectory();
- for (auto const& cmd : this->TLLCommands) {
+ cmStateDirectory cmDir = impl->Makefile->GetStateSnapshot().GetDirectory();
+ for (auto const& cmd : impl->TLLCommands) {
if (cmd.first == sig) {
cmListFileContext lfc = cmd.second;
lfc.FilePath = cmDir.ConvertToRelPathIfNotContained(
- this->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath);
+ impl->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath);
s << " * " << lfc << std::endl;
}
}
}
+std::string const& cmTarget::GetInstallPath() const
+{
+ return impl->InstallPath;
+}
+
+void cmTarget::SetInstallPath(std::string const& name)
+{
+ impl->InstallPath = name;
+}
+
+std::string const& cmTarget::GetRuntimeInstallPath() const
+{
+ return impl->RuntimeInstallPath;
+}
+
+void cmTarget::SetRuntimeInstallPath(std::string const& name)
+{
+ impl->RuntimeInstallPath = name;
+}
+
+bool cmTarget::GetHaveInstallRule() const
+{
+ return impl->HaveInstallRule;
+}
+
+void cmTarget::SetHaveInstallRule(bool hir)
+{
+ impl->HaveInstallRule = hir;
+}
+
+bool cmTarget::GetIsGeneratorProvided() const
+{
+ return impl->IsGeneratorProvided;
+}
+
+void cmTarget::SetIsGeneratorProvided(bool igp)
+{
+ impl->IsGeneratorProvided = igp;
+}
+
+cmTarget::LinkLibraryVectorType const& cmTarget::GetOriginalLinkLibraries()
+ const
+{
+ return impl->OriginalLinkLibraries;
+}
+
void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib,
cmTargetLinkLibraryType llt)
{
@@ -785,11 +900,11 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
(tgt &&
(tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) ||
- (this->Name == lib)) {
+ (impl->Name == lib)) {
return;
}
- this->OriginalLinkLibraries.emplace_back(lib, llt);
+ impl->OriginalLinkLibraries.emplace_back(lib, llt);
// Add the explicit dependency information for libraries. This is
// simply a set of libraries separated by ";". There should always
@@ -799,11 +914,11 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
// may be purposefully duplicated to handle recursive dependencies,
// and we removing one instance will break the link line. Duplicates
// will be appropriately eliminated at emit time.
- if (this->TargetTypeValue >= cmStateEnums::STATIC_LIBRARY &&
- this->TargetTypeValue <= cmStateEnums::MODULE_LIBRARY &&
+ if (impl->TargetType >= cmStateEnums::STATIC_LIBRARY &&
+ impl->TargetType <= cmStateEnums::MODULE_LIBRARY &&
(this->GetPolicyStatusCMP0073() == cmPolicies::OLD ||
this->GetPolicyStatusCMP0073() == cmPolicies::WARN)) {
- std::string targetEntry = this->Name;
+ std::string targetEntry = impl->Name;
targetEntry += "_LIB_DEPENDS";
std::string dependencies;
const char* old_val = mf.GetDefinition(targetEntry);
@@ -831,94 +946,99 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
void cmTarget::AddSystemIncludeDirectories(const std::set<std::string>& incs)
{
- this->SystemIncludeDirectories.insert(incs.begin(), incs.end());
+ impl->SystemIncludeDirectories.insert(incs.begin(), incs.end());
+}
+
+std::set<std::string> const& cmTarget::GetSystemIncludeDirectories() const
+{
+ return impl->SystemIncludeDirectories;
}
cmStringRange cmTarget::GetIncludeDirectoriesEntries() const
{
- return cmMakeRange(this->Internal->IncludeDirectoriesEntries);
+ return cmMakeRange(impl->IncludeDirectoriesEntries);
}
cmBacktraceRange cmTarget::GetIncludeDirectoriesBacktraces() const
{
- return cmMakeRange(this->Internal->IncludeDirectoriesBacktraces);
+ return cmMakeRange(impl->IncludeDirectoriesBacktraces);
}
cmStringRange cmTarget::GetCompileOptionsEntries() const
{
- return cmMakeRange(this->Internal->CompileOptionsEntries);
+ return cmMakeRange(impl->CompileOptionsEntries);
}
cmBacktraceRange cmTarget::GetCompileOptionsBacktraces() const
{
- return cmMakeRange(this->Internal->CompileOptionsBacktraces);
+ return cmMakeRange(impl->CompileOptionsBacktraces);
}
cmStringRange cmTarget::GetCompileFeaturesEntries() const
{
- return cmMakeRange(this->Internal->CompileFeaturesEntries);
+ return cmMakeRange(impl->CompileFeaturesEntries);
}
cmBacktraceRange cmTarget::GetCompileFeaturesBacktraces() const
{
- return cmMakeRange(this->Internal->CompileFeaturesBacktraces);
+ return cmMakeRange(impl->CompileFeaturesBacktraces);
}
cmStringRange cmTarget::GetCompileDefinitionsEntries() const
{
- return cmMakeRange(this->Internal->CompileDefinitionsEntries);
+ return cmMakeRange(impl->CompileDefinitionsEntries);
}
cmBacktraceRange cmTarget::GetCompileDefinitionsBacktraces() const
{
- return cmMakeRange(this->Internal->CompileDefinitionsBacktraces);
+ return cmMakeRange(impl->CompileDefinitionsBacktraces);
}
cmStringRange cmTarget::GetSourceEntries() const
{
- return cmMakeRange(this->Internal->SourceEntries);
+ return cmMakeRange(impl->SourceEntries);
}
cmBacktraceRange cmTarget::GetSourceBacktraces() const
{
- return cmMakeRange(this->Internal->SourceBacktraces);
+ return cmMakeRange(impl->SourceBacktraces);
}
cmStringRange cmTarget::GetLinkOptionsEntries() const
{
- return cmMakeRange(this->Internal->LinkOptionsEntries);
+ return cmMakeRange(impl->LinkOptionsEntries);
}
cmBacktraceRange cmTarget::GetLinkOptionsBacktraces() const
{
- return cmMakeRange(this->Internal->LinkOptionsBacktraces);
+ return cmMakeRange(impl->LinkOptionsBacktraces);
}
cmStringRange cmTarget::GetLinkDirectoriesEntries() const
{
- return cmMakeRange(this->Internal->LinkDirectoriesEntries);
+ return cmMakeRange(impl->LinkDirectoriesEntries);
}
cmBacktraceRange cmTarget::GetLinkDirectoriesBacktraces() const
{
- return cmMakeRange(this->Internal->LinkDirectoriesBacktraces);
+ return cmMakeRange(impl->LinkDirectoriesBacktraces);
}
cmStringRange cmTarget::GetLinkImplementationEntries() const
{
- return cmMakeRange(this->Internal->LinkImplementationPropertyEntries);
+ return cmMakeRange(impl->LinkImplementationPropertyEntries);
}
cmBacktraceRange cmTarget::GetLinkImplementationBacktraces() const
{
- return cmMakeRange(this->Internal->LinkImplementationPropertyBacktraces);
+ return cmMakeRange(impl->LinkImplementationPropertyBacktraces);
}
void cmTarget::SetProperty(const std::string& prop, const char* value)
{
if (!cmTargetPropertyComputer::PassesWhitelist(
- this->GetType(), prop, this->Makefile->GetMessenger(),
- this->Makefile->GetBacktrace())) {
+ this->GetType(), prop, impl->Makefile->GetMessenger(),
+ impl->Makefile->GetBacktrace())) {
return;
}
#define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP
@@ -940,133 +1060,133 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
std::ostringstream e;
e << "MANUALLY_ADDED_DEPENDENCIES property is read-only\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == propNAME) {
std::ostringstream e;
e << "NAME property is read-only\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == propTYPE) {
std::ostringstream e;
e << "TYPE property is read-only\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == propEXPORT_NAME && this->IsImported()) {
std::ostringstream e;
e << "EXPORT_NAME property can't be set on imported targets (\""
- << this->Name << "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ << impl->Name << "\")\n";
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == propSOURCES && this->IsImported()) {
std::ostringstream e;
- e << "SOURCES property can't be set on imported targets (\"" << this->Name
+ e << "SOURCES property can't be set on imported targets (\"" << impl->Name
<< "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == propIMPORTED_GLOBAL && !this->IsImported()) {
std::ostringstream e;
e << "IMPORTED_GLOBAL property can't be set on non-imported targets (\""
- << this->Name << "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ << impl->Name << "\")\n";
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == propINCLUDE_DIRECTORIES) {
- this->Internal->IncludeDirectoriesEntries.clear();
- this->Internal->IncludeDirectoriesBacktraces.clear();
+ impl->IncludeDirectoriesEntries.clear();
+ impl->IncludeDirectoriesBacktraces.clear();
if (value) {
- this->Internal->IncludeDirectoriesEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt);
+ impl->IncludeDirectoriesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->IncludeDirectoriesBacktraces.push_back(lfbt);
}
} else if (prop == propCOMPILE_OPTIONS) {
- this->Internal->CompileOptionsEntries.clear();
- this->Internal->CompileOptionsBacktraces.clear();
+ impl->CompileOptionsEntries.clear();
+ impl->CompileOptionsBacktraces.clear();
if (value) {
- this->Internal->CompileOptionsEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->CompileOptionsBacktraces.push_back(lfbt);
+ impl->CompileOptionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->CompileOptionsBacktraces.push_back(lfbt);
}
} else if (prop == propCOMPILE_FEATURES) {
- this->Internal->CompileFeaturesEntries.clear();
- this->Internal->CompileFeaturesBacktraces.clear();
+ impl->CompileFeaturesEntries.clear();
+ impl->CompileFeaturesBacktraces.clear();
if (value) {
- this->Internal->CompileFeaturesEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->CompileFeaturesBacktraces.push_back(lfbt);
+ impl->CompileFeaturesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->CompileFeaturesBacktraces.push_back(lfbt);
}
} else if (prop == propCOMPILE_DEFINITIONS) {
- this->Internal->CompileDefinitionsEntries.clear();
- this->Internal->CompileDefinitionsBacktraces.clear();
+ impl->CompileDefinitionsEntries.clear();
+ impl->CompileDefinitionsBacktraces.clear();
if (value) {
- this->Internal->CompileDefinitionsEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
+ impl->CompileDefinitionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->CompileDefinitionsBacktraces.push_back(lfbt);
}
} else if (prop == propLINK_OPTIONS) {
- this->Internal->LinkOptionsEntries.clear();
- this->Internal->LinkOptionsBacktraces.clear();
+ impl->LinkOptionsEntries.clear();
+ impl->LinkOptionsBacktraces.clear();
if (value) {
- this->Internal->LinkOptionsEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->LinkOptionsBacktraces.push_back(lfbt);
+ impl->LinkOptionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->LinkOptionsBacktraces.push_back(lfbt);
}
} else if (prop == propLINK_DIRECTORIES) {
- this->Internal->LinkDirectoriesEntries.clear();
- this->Internal->LinkDirectoriesBacktraces.clear();
+ impl->LinkDirectoriesEntries.clear();
+ impl->LinkDirectoriesBacktraces.clear();
if (value) {
- this->Internal->LinkDirectoriesEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->LinkDirectoriesBacktraces.push_back(lfbt);
+ impl->LinkDirectoriesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->LinkDirectoriesBacktraces.push_back(lfbt);
}
} else if (prop == propLINK_LIBRARIES) {
- this->Internal->LinkImplementationPropertyEntries.clear();
- this->Internal->LinkImplementationPropertyBacktraces.clear();
+ impl->LinkImplementationPropertyEntries.clear();
+ impl->LinkImplementationPropertyBacktraces.clear();
if (value) {
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->LinkImplementationPropertyEntries.emplace_back(value);
- this->Internal->LinkImplementationPropertyBacktraces.push_back(lfbt);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->LinkImplementationPropertyEntries.emplace_back(value);
+ impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
}
} else if (prop == propSOURCES) {
- this->Internal->SourceEntries.clear();
- this->Internal->SourceBacktraces.clear();
+ impl->SourceEntries.clear();
+ impl->SourceBacktraces.clear();
if (value) {
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->SourceEntries.emplace_back(value);
- this->Internal->SourceBacktraces.push_back(lfbt);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->SourceEntries.emplace_back(value);
+ impl->SourceBacktraces.push_back(lfbt);
}
} else if (prop == propIMPORTED_GLOBAL) {
if (!cmSystemTools::IsOn(value)) {
std::ostringstream e;
e << "IMPORTED_GLOBAL property can't be set to FALSE on targets (\""
- << this->Name << "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ << impl->Name << "\")\n";
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
/* no need to change anything if value does not change */
- if (!this->ImportedGloballyVisible) {
- this->ImportedGloballyVisible = true;
+ if (!impl->ImportedGloballyVisible) {
+ impl->ImportedGloballyVisible = true;
this->GetGlobalGenerator()->IndexTarget(this);
}
} else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME") &&
- !this->CheckImportedLibName(prop, value ? value : "")) {
+ !impl->CheckImportedLibName(prop, value ? value : "")) {
/* error was reported by check method */
} else if (prop == propCUDA_PTX_COMPILATION &&
this->GetType() != cmStateEnums::OBJECT_LIBRARY) {
std::ostringstream e;
e << "CUDA_PTX_COMPILATION property can only be applied to OBJECT "
"targets (\""
- << this->Name << "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ << impl->Name << "\")\n";
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
} else {
- this->Properties.SetProperty(prop, value);
+ impl->Properties.SetProperty(prop, value);
}
}
@@ -1074,89 +1194,89 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value,
bool asString)
{
if (!cmTargetPropertyComputer::PassesWhitelist(
- this->GetType(), prop, this->Makefile->GetMessenger(),
- this->Makefile->GetBacktrace())) {
+ this->GetType(), prop, impl->Makefile->GetMessenger(),
+ impl->Makefile->GetBacktrace())) {
return;
}
if (prop == "NAME") {
std::ostringstream e;
e << "NAME property is read-only\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == "EXPORT_NAME" && this->IsImported()) {
std::ostringstream e;
e << "EXPORT_NAME property can't be set on imported targets (\""
- << this->Name << "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ << impl->Name << "\")\n";
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == "SOURCES" && this->IsImported()) {
std::ostringstream e;
- e << "SOURCES property can't be set on imported targets (\"" << this->Name
+ e << "SOURCES property can't be set on imported targets (\"" << impl->Name
<< "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == "IMPORTED_GLOBAL") {
std::ostringstream e;
e << "IMPORTED_GLOBAL property can't be appended, only set on imported "
"targets (\""
- << this->Name << "\")\n";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ << impl->Name << "\")\n";
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (prop == "INCLUDE_DIRECTORIES") {
if (value && *value) {
- this->Internal->IncludeDirectoriesEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->IncludeDirectoriesBacktraces.push_back(lfbt);
+ impl->IncludeDirectoriesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->IncludeDirectoriesBacktraces.push_back(lfbt);
}
} else if (prop == "COMPILE_OPTIONS") {
if (value && *value) {
- this->Internal->CompileOptionsEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->CompileOptionsBacktraces.push_back(lfbt);
+ impl->CompileOptionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->CompileOptionsBacktraces.push_back(lfbt);
}
} else if (prop == "COMPILE_FEATURES") {
if (value && *value) {
- this->Internal->CompileFeaturesEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->CompileFeaturesBacktraces.push_back(lfbt);
+ impl->CompileFeaturesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->CompileFeaturesBacktraces.push_back(lfbt);
}
} else if (prop == "COMPILE_DEFINITIONS") {
if (value && *value) {
- this->Internal->CompileDefinitionsEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
+ impl->CompileDefinitionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->CompileDefinitionsBacktraces.push_back(lfbt);
}
} else if (prop == "LINK_OPTIONS") {
if (value && *value) {
- this->Internal->LinkOptionsEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->LinkOptionsBacktraces.push_back(lfbt);
+ impl->LinkOptionsEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->LinkOptionsBacktraces.push_back(lfbt);
}
} else if (prop == "LINK_DIRECTORIES") {
if (value && *value) {
- this->Internal->LinkDirectoriesEntries.emplace_back(value);
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->LinkDirectoriesBacktraces.push_back(lfbt);
+ impl->LinkDirectoriesEntries.emplace_back(value);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->LinkDirectoriesBacktraces.push_back(lfbt);
}
} else if (prop == "LINK_LIBRARIES") {
if (value && *value) {
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->LinkImplementationPropertyEntries.emplace_back(value);
- this->Internal->LinkImplementationPropertyBacktraces.push_back(lfbt);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->LinkImplementationPropertyEntries.emplace_back(value);
+ impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
}
} else if (prop == "SOURCES") {
- cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- this->Internal->SourceEntries.emplace_back(value);
- this->Internal->SourceBacktraces.push_back(lfbt);
+ cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
+ impl->SourceEntries.emplace_back(value);
+ impl->SourceBacktraces.push_back(lfbt);
} else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME")) {
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
prop + " property may not be APPENDed.");
} else {
- this->Properties.AppendProperty(prop, value, asString);
+ impl->Properties.AppendProperty(prop, value, asString);
}
}
@@ -1169,17 +1289,17 @@ void cmTarget::AppendBuildInterfaceIncludes()
!this->IsExecutableWithExports()) {
return;
}
- if (this->BuildInterfaceIncludesAppended) {
+ if (impl->BuildInterfaceIncludesAppended) {
return;
}
- this->BuildInterfaceIncludesAppended = true;
+ impl->BuildInterfaceIncludesAppended = true;
- if (this->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")) {
- std::string dirs = this->Makefile->GetCurrentBinaryDirectory();
+ if (impl->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")) {
+ std::string dirs = impl->Makefile->GetCurrentBinaryDirectory();
if (!dirs.empty()) {
dirs += ';';
}
- dirs += this->Makefile->GetCurrentSourceDirectory();
+ dirs += impl->Makefile->GetCurrentSourceDirectory();
if (!dirs.empty()) {
this->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
("$<BUILD_INTERFACE:" + dirs + ">").c_str());
@@ -1191,67 +1311,66 @@ void cmTarget::InsertInclude(std::string const& entry,
cmListFileBacktrace const& bt, bool before)
{
std::vector<std::string>::iterator position = before
- ? this->Internal->IncludeDirectoriesEntries.begin()
- : this->Internal->IncludeDirectoriesEntries.end();
+ ? impl->IncludeDirectoriesEntries.begin()
+ : impl->IncludeDirectoriesEntries.end();
std::vector<cmListFileBacktrace>::iterator btPosition = before
- ? this->Internal->IncludeDirectoriesBacktraces.begin()
- : this->Internal->IncludeDirectoriesBacktraces.end();
+ ? impl->IncludeDirectoriesBacktraces.begin()
+ : impl->IncludeDirectoriesBacktraces.end();
- this->Internal->IncludeDirectoriesEntries.insert(position, entry);
- this->Internal->IncludeDirectoriesBacktraces.insert(btPosition, bt);
+ impl->IncludeDirectoriesEntries.insert(position, entry);
+ impl->IncludeDirectoriesBacktraces.insert(btPosition, bt);
}
void cmTarget::InsertCompileOption(std::string const& entry,
cmListFileBacktrace const& bt, bool before)
{
std::vector<std::string>::iterator position = before
- ? this->Internal->CompileOptionsEntries.begin()
- : this->Internal->CompileOptionsEntries.end();
+ ? impl->CompileOptionsEntries.begin()
+ : impl->CompileOptionsEntries.end();
std::vector<cmListFileBacktrace>::iterator btPosition = before
- ? this->Internal->CompileOptionsBacktraces.begin()
- : this->Internal->CompileOptionsBacktraces.end();
+ ? impl->CompileOptionsBacktraces.begin()
+ : impl->CompileOptionsBacktraces.end();
- this->Internal->CompileOptionsEntries.insert(position, entry);
- this->Internal->CompileOptionsBacktraces.insert(btPosition, bt);
+ impl->CompileOptionsEntries.insert(position, entry);
+ impl->CompileOptionsBacktraces.insert(btPosition, bt);
}
void cmTarget::InsertCompileDefinition(std::string const& entry,
cmListFileBacktrace const& bt)
{
- this->Internal->CompileDefinitionsEntries.push_back(entry);
- this->Internal->CompileDefinitionsBacktraces.push_back(bt);
+ impl->CompileDefinitionsEntries.push_back(entry);
+ impl->CompileDefinitionsBacktraces.push_back(bt);
}
void cmTarget::InsertLinkOption(std::string const& entry,
cmListFileBacktrace const& bt, bool before)
{
- std::vector<std::string>::iterator position = before
- ? this->Internal->LinkOptionsEntries.begin()
- : this->Internal->LinkOptionsEntries.end();
+ std::vector<std::string>::iterator position =
+ before ? impl->LinkOptionsEntries.begin() : impl->LinkOptionsEntries.end();
std::vector<cmListFileBacktrace>::iterator btPosition = before
- ? this->Internal->LinkOptionsBacktraces.begin()
- : this->Internal->LinkOptionsBacktraces.end();
+ ? impl->LinkOptionsBacktraces.begin()
+ : impl->LinkOptionsBacktraces.end();
- this->Internal->LinkOptionsEntries.insert(position, entry);
- this->Internal->LinkOptionsBacktraces.insert(btPosition, bt);
+ impl->LinkOptionsEntries.insert(position, entry);
+ impl->LinkOptionsBacktraces.insert(btPosition, bt);
}
void cmTarget::InsertLinkDirectory(std::string const& entry,
cmListFileBacktrace const& bt, bool before)
{
std::vector<std::string>::iterator position = before
- ? this->Internal->LinkDirectoriesEntries.begin()
- : this->Internal->LinkDirectoriesEntries.end();
+ ? impl->LinkDirectoriesEntries.begin()
+ : impl->LinkDirectoriesEntries.end();
std::vector<cmListFileBacktrace>::iterator btPosition = before
- ? this->Internal->LinkDirectoriesBacktraces.begin()
- : this->Internal->LinkDirectoriesBacktraces.end();
+ ? impl->LinkDirectoriesBacktraces.begin()
+ : impl->LinkDirectoriesBacktraces.end();
- this->Internal->LinkDirectoriesEntries.insert(position, entry);
- this->Internal->LinkDirectoriesBacktraces.insert(btPosition, bt);
+ impl->LinkDirectoriesEntries.insert(position, entry);
+ impl->LinkDirectoriesBacktraces.insert(btPosition, bt);
}
static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop,
@@ -1402,12 +1521,12 @@ const char* cmTarget::GetProperty(const std::string& prop) const
}
if (specialProps.count(prop)) {
if (prop == propLINK_LIBRARIES) {
- if (this->Internal->LinkImplementationPropertyEntries.empty()) {
+ if (impl->LinkImplementationPropertyEntries.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Internal->LinkImplementationPropertyEntries, ";");
+ output = cmJoin(impl->LinkImplementationPropertyEntries, ";");
return output.c_str();
}
// the type property returns what type the target is
@@ -1415,67 +1534,67 @@ const char* cmTarget::GetProperty(const std::string& prop) const
return cmState::GetTargetTypeName(this->GetType());
}
if (prop == propINCLUDE_DIRECTORIES) {
- if (this->Internal->IncludeDirectoriesEntries.empty()) {
+ if (impl->IncludeDirectoriesEntries.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Internal->IncludeDirectoriesEntries, ";");
+ output = cmJoin(impl->IncludeDirectoriesEntries, ";");
return output.c_str();
}
if (prop == propCOMPILE_FEATURES) {
- if (this->Internal->CompileFeaturesEntries.empty()) {
+ if (impl->CompileFeaturesEntries.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Internal->CompileFeaturesEntries, ";");
+ output = cmJoin(impl->CompileFeaturesEntries, ";");
return output.c_str();
}
if (prop == propCOMPILE_OPTIONS) {
- if (this->Internal->CompileOptionsEntries.empty()) {
+ if (impl->CompileOptionsEntries.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Internal->CompileOptionsEntries, ";");
+ output = cmJoin(impl->CompileOptionsEntries, ";");
return output.c_str();
}
if (prop == propCOMPILE_DEFINITIONS) {
- if (this->Internal->CompileDefinitionsEntries.empty()) {
+ if (impl->CompileDefinitionsEntries.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Internal->CompileDefinitionsEntries, ";");
+ output = cmJoin(impl->CompileDefinitionsEntries, ";");
return output.c_str();
}
if (prop == propLINK_OPTIONS) {
- if (this->Internal->LinkOptionsEntries.empty()) {
+ if (impl->LinkOptionsEntries.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Internal->LinkOptionsEntries, ";");
+ output = cmJoin(impl->LinkOptionsEntries, ";");
return output.c_str();
}
if (prop == propLINK_DIRECTORIES) {
- if (this->Internal->LinkDirectoriesEntries.empty()) {
+ if (impl->LinkDirectoriesEntries.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Internal->LinkDirectoriesEntries, ";");
+ output = cmJoin(impl->LinkDirectoriesEntries, ";");
return output.c_str();
}
if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
- if (this->Utilities.empty()) {
+ if (impl->Utilities.empty()) {
return nullptr;
}
static std::string output;
- output = cmJoin(this->Utilities, ";");
+ output = cmJoin(impl->Utilities, ";");
return output.c_str();
}
if (prop == propIMPORTED) {
@@ -1488,27 +1607,25 @@ const char* cmTarget::GetProperty(const std::string& prop) const
return this->GetName().c_str();
}
if (prop == propBINARY_DIR) {
- return this->GetMakefile()
- ->GetStateSnapshot()
+ return impl->Makefile->GetStateSnapshot()
.GetDirectory()
.GetCurrentBinary()
.c_str();
}
if (prop == propSOURCE_DIR) {
- return this->GetMakefile()
- ->GetStateSnapshot()
+ return impl->Makefile->GetStateSnapshot()
.GetDirectory()
.GetCurrentSource()
.c_str();
}
}
- const char* retVal = this->Properties.GetPropertyValue(prop);
+ const char* retVal = impl->Properties.GetPropertyValue(prop);
if (!retVal) {
- const bool chain = this->GetMakefile()->GetState()->IsPropertyChained(
- prop, cmProperty::TARGET);
+ const bool chain =
+ impl->Makefile->GetState()->IsPropertyChained(prop, cmProperty::TARGET);
if (chain) {
- return this->Makefile->GetStateSnapshot().GetDirectory().GetProperty(
+ return impl->Makefile->GetStateSnapshot().GetDirectory().GetProperty(
prop, chain);
}
}
@@ -1529,6 +1646,21 @@ bool cmTarget::GetPropertyAsBool(const std::string& prop) const
return cmSystemTools::IsOn(this->GetProperty(prop));
}
+cmPropertyMap const& cmTarget::GetProperties() const
+{
+ return impl->Properties;
+}
+
+bool cmTarget::IsImported() const
+{
+ return impl->IsImportedTarget;
+}
+
+bool cmTarget::IsImportedGloballyVisible() const
+{
+ return impl->ImportedGloballyVisible;
+}
+
const char* cmTarget::GetSuffixVariableInternal(
cmStateEnums::ArtifactType artifact) const
{
@@ -1556,7 +1688,7 @@ const char* cmTarget::GetSuffixVariableInternal(
case cmStateEnums::RuntimeBinaryArtifact:
// Android GUI application packages store the native
// binary as a shared library.
- return (this->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")
+ return (impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")
? "CMAKE_SHARED_LIBRARY_SUFFIX"
: "CMAKE_EXECUTABLE_SUFFIX");
case cmStateEnums::ImportLibraryArtifact:
@@ -1596,7 +1728,7 @@ const char* cmTarget::GetPrefixVariableInternal(
case cmStateEnums::RuntimeBinaryArtifact:
// Android GUI application packages store the native
// binary as a shared library.
- return (this->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")
+ return (impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")
? "CMAKE_SHARED_LIBRARY_PREFIX"
: "");
case cmStateEnums::ImportLibraryArtifact:
@@ -1670,25 +1802,11 @@ std::string cmTarget::ImportedGetFullPath(
return result;
}
-void cmTarget::SetPropertyDefault(const std::string& property,
- const char* default_value)
-{
- // Compute the name of the variable holding the default value.
- std::string var = "CMAKE_";
- var += property;
-
- if (const char* value = this->Makefile->GetDefinition(var)) {
- this->SetProperty(property, value);
- } else if (default_value) {
- this->SetProperty(property, default_value);
- }
-}
-
-bool cmTarget::CheckImportedLibName(std::string const& prop,
- std::string const& value) const
+bool cmTargetInternals::CheckImportedLibName(std::string const& prop,
+ std::string const& value) const
{
- if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY ||
- !this->IsImported()) {
+ if (this->TargetType != cmStateEnums::INTERFACE_LIBRARY ||
+ !this->IsImportedTarget) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
prop +
@@ -1748,7 +1866,9 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config,
// If we needed to find one of the mapped configurations but did not
// On a DLL platform there may be only IMPORTED_IMPLIB for a shared
// library or an executable with exports.
- bool allowImp = this->HasImportLibrary();
+ bool allowImp = (impl->DLLPlatform &&
+ (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->IsExecutableWithExports()));
// If a mapping was found, check its configurations.
for (std::vector<std::string>::const_iterator mci = mappedConfigs.begin();
@@ -1851,37 +1971,3 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config,
return true;
}
-
-cmTargetInternalPointer::cmTargetInternalPointer()
-{
- this->Pointer = new cmTargetInternals;
-}
-
-cmTargetInternalPointer::cmTargetInternalPointer(
- cmTargetInternalPointer const& r)
-{
- // Ideally cmTarget instances should never be copied. However until
- // we can make a sweep to remove that, this copy constructor avoids
- // allowing the resources (Internals) to be copied.
- this->Pointer = new cmTargetInternals(*r.Pointer);
-}
-
-cmTargetInternalPointer::~cmTargetInternalPointer()
-{
- delete this->Pointer;
-}
-
-cmTargetInternalPointer& cmTargetInternalPointer::operator=(
- cmTargetInternalPointer const& r)
-{
- if (this == &r) {
- return *this;
- } // avoid warning on HP about self check
- // Ideally cmTarget instances should never be copied. However until
- // we can make a sweep to remove that, this copy constructor avoids
- // allowing the resources (Internals) to be copied.
- cmTargetInternals* oldPointer = this->Pointer;
- this->Pointer = new cmTargetInternals(*r.Pointer);
- delete oldPointer;
- return *this;
-}
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 24b37423e..fdcca47b8 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -6,45 +6,30 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <iosfwd>
+#include <memory> // IWYU pragma: keep
#include <set>
#include <string>
-#include <unordered_map>
#include <utility>
#include <vector>
#include "cmAlgorithms.h"
-#include "cmCustomCommand.h"
#include "cmListFileCache.h"
#include "cmPolicies.h"
-#include "cmPropertyMap.h"
#include "cmStateTypes.h"
#include "cmTargetLinkLibraryType.h"
+class cmCustomCommand;
class cmGlobalGenerator;
class cmMakefile;
class cmMessenger;
+class cmPropertyMap;
class cmSourceFile;
class cmTargetInternals;
-class cmTargetInternalPointer
-{
-public:
- cmTargetInternalPointer();
- cmTargetInternalPointer(cmTargetInternalPointer const& r);
- ~cmTargetInternalPointer();
- cmTargetInternalPointer& operator=(cmTargetInternalPointer const& r);
- cmTargetInternals* operator->() const { return this->Pointer; }
- cmTargetInternals* Get() const { return this->Pointer; }
-
-private:
- cmTargetInternals* Pointer;
-};
-
/** \class cmTarget
* \brief Represent a library or executable target loaded from a makefile.
*
- * cmTarget represents a target loaded from
- * a makefile.
+ * cmTarget represents a target loaded from a makefile.
*/
class cmTarget
{
@@ -56,9 +41,6 @@ public:
VisibilityImportedGlobally
};
- cmTarget(std::string const& name, cmStateEnums::TargetType type,
- Visibility vis, cmMakefile* mf);
-
enum CustomCommandType
{
PRE_BUILD,
@@ -66,77 +48,68 @@ public:
POST_BUILD
};
- /**
- * Return the type of target.
- */
- cmStateEnums::TargetType GetType() const { return this->TargetTypeValue; }
+ cmTarget(std::string const& name, cmStateEnums::TargetType type,
+ Visibility vis, cmMakefile* mf);
+
+ cmTarget(cmTarget const&) = delete;
+ cmTarget(cmTarget&&) noexcept;
+ ~cmTarget();
+ cmTarget& operator=(cmTarget const&) = delete;
+ cmTarget& operator=(cmTarget&&) noexcept;
+
+ //! Return the type of target.
+ cmStateEnums::TargetType GetType() const;
+
+ //! Get the cmMakefile that owns this target.
+ cmMakefile* GetMakefile() const;
+
+ //! Return the global generator.
cmGlobalGenerator* GetGlobalGenerator() const;
- ///! Set/Get the name of the target
- const std::string& GetName() const { return this->Name; }
+ //! Set/Get the name of the target
+ const std::string& GetName() const;
+
+ //! Get the policy map
+ cmPolicies::PolicyMap const& GetPolicyMap() const;
- /** Get the cmMakefile that owns this target. */
- cmMakefile* GetMakefile() const { return this->Makefile; }
+ //! Get policy status
+ cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID policy) const;
#define DECLARE_TARGET_POLICY(POLICY) \
cmPolicies::PolicyStatus GetPolicyStatus##POLICY() const \
{ \
- return this->PolicyMap.Get(cmPolicies::POLICY); \
+ return this->GetPolicyStatus(cmPolicies::POLICY); \
}
CM_FOR_EACH_TARGET_POLICY(DECLARE_TARGET_POLICY)
#undef DECLARE_TARGET_POLICY
- /**
- * Get the list of the custom commands for this target
- */
- std::vector<cmCustomCommand> const& GetPreBuildCommands() const
- {
- return this->PreBuildCommands;
- }
- std::vector<cmCustomCommand> const& GetPreLinkCommands() const
- {
- return this->PreLinkCommands;
- }
- std::vector<cmCustomCommand> const& GetPostBuildCommands() const
- {
- return this->PostBuildCommands;
- }
- void AddPreBuildCommand(cmCustomCommand const& cmd)
- {
- this->PreBuildCommands.push_back(cmd);
- }
- void AddPreLinkCommand(cmCustomCommand const& cmd)
- {
- this->PreLinkCommands.push_back(cmd);
- }
- void AddPostBuildCommand(cmCustomCommand const& cmd)
- {
- this->PostBuildCommands.push_back(cmd);
- }
+ //! Get the list of the PRE_BUILD custom commands for this target
+ std::vector<cmCustomCommand> const& GetPreBuildCommands() const;
+ void AddPreBuildCommand(cmCustomCommand const& cmd);
- /**
- * Add sources to the target.
- */
+ //! Get the list of the PRE_LINK custom commands for this target
+ std::vector<cmCustomCommand> const& GetPreLinkCommands() const;
+ void AddPreLinkCommand(cmCustomCommand const& cmd);
+
+ //! Get the list of the POST_BUILD custom commands for this target
+ std::vector<cmCustomCommand> const& GetPostBuildCommands() const;
+ void AddPostBuildCommand(cmCustomCommand const& cmd);
+
+ //! Add sources to the target.
void AddSources(std::vector<std::string> const& srcs);
void AddTracedSources(std::vector<std::string> const& srcs);
cmSourceFile* AddSourceCMP0049(const std::string& src);
cmSourceFile* AddSource(const std::string& src, bool before = false);
- //* how we identify a library, by name and type
+ //! how we identify a library, by name and type
typedef std::pair<std::string, cmTargetLinkLibraryType> LibraryID;
-
typedef std::vector<LibraryID> LinkLibraryVectorType;
- const LinkLibraryVectorType& GetOriginalLinkLibraries() const
- {
- return this->OriginalLinkLibraries;
- }
+ LinkLibraryVectorType const& GetOriginalLinkLibraries() const;
- /**
- * Clear the dependency information recorded for this target, if any.
- */
+ //! Clear the dependency information recorded for this target, if any.
void ClearDependencyInformation(cmMakefile& mf);
void AddLinkLibrary(cmMakefile& mf, const std::string& lib,
@@ -157,83 +130,69 @@ public:
* Set the path where this target should be installed. This is relative to
* INSTALL_PREFIX
*/
- std::string GetInstallPath() const { return this->InstallPath; }
- void SetInstallPath(const char* name) { this->InstallPath = name; }
+ std::string const& GetInstallPath() const;
+ void SetInstallPath(std::string const& name);
/**
* Set the path where this target (if it has a runtime part) should be
* installed. This is relative to INSTALL_PREFIX
*/
- std::string GetRuntimeInstallPath() const
- {
- return this->RuntimeInstallPath;
- }
- void SetRuntimeInstallPath(const char* name)
- {
- this->RuntimeInstallPath = name;
- }
+ std::string const& GetRuntimeInstallPath() const;
+ void SetRuntimeInstallPath(std::string const& name);
/**
* Get/Set whether there is an install rule for this target.
*/
- bool GetHaveInstallRule() const { return this->HaveInstallRule; }
- void SetHaveInstallRule(bool h) { this->HaveInstallRule = h; }
+ bool GetHaveInstallRule() const;
+ void SetHaveInstallRule(bool hir);
/**
* Get/Set whether this target was auto-created by a generator.
*/
- bool GetIsGeneratorProvided() const { return this->IsGeneratorProvided; }
- void SetIsGeneratorProvided(bool igp) { this->IsGeneratorProvided = igp; }
+ bool GetIsGeneratorProvided() const;
+ void SetIsGeneratorProvided(bool igp);
- /** Add a utility on which this project depends. A utility is an executable
+ /**
+ * Add a utility on which this project depends. A utility is an executable
* name as would be specified to the ADD_EXECUTABLE or UTILITY_SOURCE
* commands. It is not a full path nor does it have an extension.
*/
- void AddUtility(std::string const& u, cmMakefile* mf = nullptr);
- ///! Get the utilities used by this target
- std::set<BT<std::string>> const& GetUtilities() const
- {
- return this->Utilities;
- }
+ void AddUtility(std::string const& name, cmMakefile* mf = nullptr);
+ //! Get the utilities used by this target
+ std::set<BT<std::string>> const& GetUtilities() const;
- ///! Set/Get a property of this target file
+ //! Set/Get a property of this target file
void SetProperty(const std::string& prop, const char* value);
void AppendProperty(const std::string& prop, const char* value,
bool asString = false);
- ///! Might return a nullptr if the property is not set or invalid
+ //! Might return a nullptr if the property is not set or invalid
const char* GetProperty(const std::string& prop) const;
- ///! Always returns a valid pointer
+ //! Always returns a valid pointer
const char* GetSafeProperty(const std::string& prop) const;
bool GetPropertyAsBool(const std::string& prop) const;
void CheckProperty(const std::string& prop, cmMakefile* context) const;
const char* GetComputedProperty(const std::string& prop,
cmMessenger* messenger,
cmListFileBacktrace const& context) const;
+ //! Get all properties
+ cmPropertyMap const& GetProperties() const;
- bool IsImported() const { return this->IsImportedTarget; }
- bool IsImportedGloballyVisible() const
- {
- return this->ImportedGloballyVisible;
- }
-
- // Get the properties
- cmPropertyMap const& GetProperties() const { return this->Properties; }
+ bool IsImported() const;
+ bool IsImportedGloballyVisible() const;
bool GetMappedConfig(std::string const& desired_config, const char** loc,
const char** imp, std::string& suffix) const;
- /** Return whether this target is an executable with symbol exports
- enabled. */
+ //! Return whether this target is an executable with symbol exports enabled.
bool IsExecutableWithExports() const;
- /** Return whether this target is a shared library Framework on
- Apple. */
+ //! Return whether this target is a shared library Framework on Apple.
bool IsFrameworkOnApple() const;
- /** Return whether this target is an executable Bundle on Apple. */
+ //! Return whether this target is an executable Bundle on Apple.
bool IsAppBundleOnApple() const;
- /** Get a backtrace from the creation of the target. */
+ //! Get a backtrace from the creation of the target.
cmListFileBacktrace const& GetBacktrace() const;
void InsertInclude(std::string const& entry, cmListFileBacktrace const& bt,
@@ -252,11 +211,8 @@ public:
std::string GetDebugGeneratorExpressions(const std::string& value,
cmTargetLinkLibraryType llt) const;
- void AddSystemIncludeDirectories(const std::set<std::string>& incs);
- std::set<std::string> const& GetSystemIncludeDirectories() const
- {
- return this->SystemIncludeDirectories;
- }
+ void AddSystemIncludeDirectories(std::set<std::string> const& incs);
+ std::set<std::string> const& GetSystemIncludeDirectories() const;
cmStringRange GetIncludeDirectoriesEntries() const;
cmBacktraceRange GetIncludeDirectoriesBacktraces() const;
@@ -282,65 +238,25 @@ public:
cmStringRange GetLinkImplementationEntries() const;
cmBacktraceRange GetLinkImplementationBacktraces() const;
+ std::string ImportedGetFullPath(const std::string& config,
+ cmStateEnums::ArtifactType artifact) const;
+
struct StrictTargetComparison
{
bool operator()(cmTarget const* t1, cmTarget const* t2) const;
};
- std::string ImportedGetFullPath(const std::string& config,
- cmStateEnums::ArtifactType artifact) const;
-
private:
+ // Internal representation details.
+ friend class cmGeneratorTarget;
+
const char* GetSuffixVariableInternal(
cmStateEnums::ArtifactType artifact) const;
const char* GetPrefixVariableInternal(
cmStateEnums::ArtifactType artifact) const;
- // Use a makefile variable to set a default for the given property.
- // If the variable is not defined use the given default instead.
- void SetPropertyDefault(const std::string& property,
- const char* default_value);
-
- bool CheckImportedLibName(std::string const& prop,
- std::string const& value) const;
-
private:
- bool IsGeneratorProvided;
- cmPropertyMap Properties;
- std::set<std::string> SystemIncludeDirectories;
- std::set<BT<std::string>> Utilities;
- cmPolicies::PolicyMap PolicyMap;
- std::string Name;
- std::string InstallPath;
- std::string RuntimeInstallPath;
- std::vector<cmCustomCommand> PreBuildCommands;
- std::vector<cmCustomCommand> PreLinkCommands;
- std::vector<cmCustomCommand> PostBuildCommands;
- std::vector<std::pair<TLLSignature, cmListFileContext>> TLLCommands;
- LinkLibraryVectorType OriginalLinkLibraries;
- cmMakefile* Makefile;
- cmTargetInternalPointer Internal;
- cmStateEnums::TargetType TargetTypeValue;
- bool HaveInstallRule;
- bool DLLPlatform;
- bool IsAndroid;
- bool IsImportedTarget;
- bool ImportedGloballyVisible;
- bool BuildInterfaceIncludesAppended;
-
- std::string ProcessSourceItemCMP0049(const std::string& s);
-
- /** Return whether or not the target has a DLL import library. */
- bool HasImportLibrary() const;
-
- // Internal representation details.
- friend class cmTargetInternals;
- friend class cmGeneratorTarget;
- friend class cmTargetTraceDependencies;
-
- cmListFileBacktrace Backtrace;
+ std::unique_ptr<cmTargetInternals> impl;
};
-typedef std::unordered_map<std::string, cmTarget> cmTargets;
-
#endif
diff --git a/Source/cmTargetPropertyComputer.cxx b/Source/cmTargetPropertyComputer.cxx
index d2c3496ed..3f763afaf 100644
--- a/Source/cmTargetPropertyComputer.cxx
+++ b/Source/cmTargetPropertyComputer.cxx
@@ -63,10 +63,13 @@ bool cmTargetPropertyComputer::WhiteListedInterfaceProperty(
builtIns.insert("COMPATIBLE_INTERFACE_NUMBER_MIN");
builtIns.insert("COMPATIBLE_INTERFACE_STRING");
builtIns.insert("EXPORT_NAME");
+ builtIns.insert("EXPORT_PROPERTIES");
builtIns.insert("IMPORTED");
builtIns.insert("IMPORTED_GLOBAL");
builtIns.insert("MANUALLY_ADDED_DEPENDENCIES");
builtIns.insert("NAME");
+ builtIns.insert("PRIVATE_HEADER");
+ builtIns.insert("PUBLIC_HEADER");
builtIns.insert("TYPE");
}
diff --git a/Source/cmTargetPropertyComputer.h b/Source/cmTargetPropertyComputer.h
index 97e4fba2c..efbf95f7f 100644
--- a/Source/cmTargetPropertyComputer.h
+++ b/Source/cmTargetPropertyComputer.h
@@ -81,7 +81,7 @@ private:
context)) {
return nullptr;
}
- const char* configName = prop.c_str() + 9;
+ std::string configName = prop.substr(9);
return ComputeLocation(tgt, configName);
}
diff --git a/Source/cmTest.h b/Source/cmTest.h
index d4839d171..88dc73089 100644
--- a/Source/cmTest.h
+++ b/Source/cmTest.h
@@ -26,14 +26,14 @@ public:
cmTest(cmMakefile* mf);
~cmTest();
- ///! Set the test name
+ //! Set the test name
void SetName(const std::string& name);
std::string GetName() const { return this->Name; }
void SetCommand(std::vector<std::string> const& command);
std::vector<std::string> const& GetCommand() const { return this->Command; }
- ///! Set/Get a property of this source file
+ //! Set/Get a property of this source file
void SetProperty(const std::string& prop, const char* value);
void AppendProperty(const std::string& prop, const char* value,
bool asString = false);
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
index 5102613eb..571cd0909 100644
--- a/Source/cmTestGenerator.cxx
+++ b/Source/cmTestGenerator.cxx
@@ -12,6 +12,7 @@
#include "cmOutputConverter.h"
#include "cmProperty.h"
#include "cmPropertyMap.h"
+#include "cmRange.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTest.h"
@@ -94,10 +95,8 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
std::string emulatorExe(emulatorWithArgs[0]);
cmSystemTools::ConvertToUnixSlashes(emulatorExe);
os << cmOutputConverter::EscapeForCMake(emulatorExe) << " ";
- for (std::vector<std::string>::const_iterator ei =
- emulatorWithArgs.begin() + 1;
- ei != emulatorWithArgs.end(); ++ei) {
- os << cmOutputConverter::EscapeForCMake(*ei) << " ";
+ for (std::string const& arg : cmMakeRange(emulatorWithArgs).advance(1)) {
+ os << cmOutputConverter::EscapeForCMake(arg) << " ";
}
}
} else {
@@ -108,11 +107,10 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
// Generate the command line with full escapes.
os << cmOutputConverter::EscapeForCMake(exe);
- for (std::vector<std::string>::const_iterator ci = command.begin() + 1;
- ci != command.end(); ++ci) {
+ for (std::string const& arg : cmMakeRange(command).advance(1)) {
os << " "
<< cmOutputConverter::EscapeForCMake(
- ge.Parse(*ci)->Evaluate(this->LG, config));
+ ge.Parse(arg)->Evaluate(this->LG, config));
}
// Finish the test command.
@@ -157,12 +155,11 @@ void cmTestGenerator::GenerateOldStyle(std::ostream& fout, Indent indent)
fout << "add_test(";
fout << this->Test->GetName() << " \"" << exe << "\"";
- for (std::vector<std::string>::const_iterator argit = command.begin() + 1;
- argit != command.end(); ++argit) {
+ for (std::string const& arg : cmMakeRange(command).advance(1)) {
// Just double-quote all arguments so they are re-parsed
// correctly by the test system.
fout << " \"";
- for (char c : *argit) {
+ for (char c : arg) {
// Escape quotes within arguments. We should escape
// backslashes too but we cannot because it makes the result
// inconsistent with previous behavior of this command.
diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx
index c57aabdc3..a92c2a05c 100644
--- a/Source/cmTryRunCommand.cxx
+++ b/Source/cmTryRunCommand.cxx
@@ -8,6 +8,7 @@
#include "cmDuration.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
@@ -145,7 +146,7 @@ bool cmTryRunCommand::InitialPass(std::vector<std::string> const& argv,
const char* compileOutput =
this->Makefile->GetDefinition(this->OutputVariable);
if (compileOutput) {
- runOutputContents = std::string(compileOutput) + runOutputContents;
+ runOutputContents = compileOutput + runOutputContents;
}
this->Makefile->AddDefinition(this->OutputVariable,
runOutputContents.c_str());
@@ -166,31 +167,28 @@ void cmTryRunCommand::RunExecutable(const std::string& runArgs,
int retVal = -1;
std::string finalCommand;
- const std::string emulator =
+ const std::string& emulator =
this->Makefile->GetSafeDefinition("CMAKE_CROSSCOMPILING_EMULATOR");
if (!emulator.empty()) {
std::vector<std::string> emulatorWithArgs;
cmSystemTools::ExpandListArgument(emulator, emulatorWithArgs);
finalCommand +=
- cmSystemTools::ConvertToRunCommandPath(emulatorWithArgs[0].c_str());
+ cmSystemTools::ConvertToRunCommandPath(emulatorWithArgs[0]);
finalCommand += " ";
- for (std::vector<std::string>::const_iterator ei =
- emulatorWithArgs.begin() + 1;
- ei != emulatorWithArgs.end(); ++ei) {
+ for (std::string const& arg : cmMakeRange(emulatorWithArgs).advance(1)) {
finalCommand += "\"";
- finalCommand += *ei;
+ finalCommand += arg;
finalCommand += "\"";
finalCommand += " ";
}
}
- finalCommand +=
- cmSystemTools::ConvertToRunCommandPath(this->OutputFile.c_str());
+ finalCommand += cmSystemTools::ConvertToRunCommandPath(this->OutputFile);
if (!runArgs.empty()) {
finalCommand += runArgs;
}
bool worked = cmSystemTools::RunSingleCommand(
- finalCommand.c_str(), out, out, &retVal, nullptr,
- cmSystemTools::OUTPUT_NONE, cmDuration::zero());
+ finalCommand, out, out, &retVal, nullptr, cmSystemTools::OUTPUT_NONE,
+ cmDuration::zero());
// set the run var
char retChar[16];
const char* retStr;
@@ -235,7 +233,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
this->RunResultVariable + "__TRYRUN_OUTPUT";
bool error = false;
- if (this->Makefile->GetDefinition(this->RunResultVariable) == nullptr) {
+ if (!this->Makefile->GetDefinition(this->RunResultVariable)) {
// if the variables doesn't exist, create it with a helpful error text
// and mark it as advanced
std::string comment;
@@ -257,8 +255,8 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
}
// is the output from the executable used ?
- if (out != nullptr) {
- if (this->Makefile->GetDefinition(internalRunOutputName) == nullptr) {
+ 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
std::string comment;
@@ -306,7 +304,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
comment += " to\n"
" the exit code (in many cases 0 for success), otherwise "
"enter \"FAILED_TO_RUN\".\n";
- if (out != nullptr) {
+ if (out) {
comment += internalRunOutputName;
comment +=
"\n contains the text the executable "
@@ -337,7 +335,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
<< this->Makefile->GetDefinition(this->RunResultVariable)
<< "\"\n CACHE STRING \"Result from TRY_RUN\" FORCE)\n\n";
- if (out != nullptr) {
+ if (out) {
file << "set( " << internalRunOutputName << " \n \""
<< this->Makefile->GetDefinition(internalRunOutputName)
<< "\"\n CACHE STRING \"Output from TRY_RUN\" FORCE)\n\n";
@@ -350,7 +348,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
"please set the following cache variables "
"appropriately:\n";
errorMessage += " " + this->RunResultVariable + " (advanced)\n";
- if (out != nullptr) {
+ if (out) {
errorMessage += " " + internalRunOutputName + " (advanced)\n";
}
errorMessage += detailsString;
@@ -358,7 +356,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs,
return;
}
- if (out != nullptr) {
+ if (out) {
(*out) = this->Makefile->GetDefinition(internalRunOutputName);
}
}
diff --git a/Source/cmUVHandlePtr.cxx b/Source/cmUVHandlePtr.cxx
index fd07d2dba..db674636c 100644
--- a/Source/cmUVHandlePtr.cxx
+++ b/Source/cmUVHandlePtr.cxx
@@ -11,19 +11,59 @@
namespace cm {
-static void close_delete(uv_handle_t* h)
+struct uv_loop_deleter
{
- free(h);
+ void operator()(uv_loop_t* loop) const;
+};
+
+void uv_loop_deleter::operator()(uv_loop_t* loop) const
+{
+ uv_run(loop, UV_RUN_DEFAULT);
+ int result = uv_loop_close(loop);
+ (void)result;
+ assert(result >= 0);
+ free(loop);
+}
+
+int uv_loop_ptr::init(void* data)
+{
+ this->reset();
+
+ this->loop.reset(static_cast<uv_loop_t*>(calloc(1, sizeof(uv_loop_t))),
+ uv_loop_deleter());
+ this->loop->data = data;
+
+ return uv_loop_init(this->loop.get());
+}
+
+void uv_loop_ptr::reset()
+{
+ this->loop.reset();
+}
+
+uv_loop_ptr::operator uv_loop_t*()
+{
+ return this->loop.get();
+}
+
+uv_loop_t* uv_loop_ptr::operator->() const noexcept
+{
+ return this->loop.get();
+}
+
+uv_loop_t* uv_loop_ptr::get() const
+{
+ return this->loop.get();
}
template <typename T>
-static void default_delete(T* type_handle)
+static void handle_default_delete(T* type_handle)
{
auto handle = reinterpret_cast<uv_handle_t*>(type_handle);
if (handle) {
assert(!uv_is_closing(handle));
if (!uv_is_closing(handle)) {
- uv_close(handle, &close_delete);
+ uv_close(handle, [](uv_handle_t* h) { free(h); });
}
}
}
@@ -34,7 +74,7 @@ static void default_delete(T* type_handle)
template <typename T>
struct uv_handle_deleter
{
- void operator()(T* type_handle) const { default_delete(type_handle); }
+ void operator()(T* type_handle) const { handle_default_delete(type_handle); }
};
template <typename T>
@@ -107,7 +147,7 @@ struct uv_handle_deleter<uv_async_t>
void operator()(uv_async_t* handle)
{
std::lock_guard<std::mutex> lock(*handleMutex);
- default_delete(handle);
+ handle_default_delete(handle);
}
};
@@ -136,7 +176,7 @@ struct uv_handle_deleter<uv_signal_t>
{
if (handle) {
uv_signal_stop(handle);
- default_delete(handle);
+ handle_default_delete(handle);
}
}
};
@@ -171,7 +211,6 @@ uv_pipe_ptr::operator uv_stream_t*() const
return reinterpret_cast<uv_stream_t*>(handle.get());
}
-#ifdef CMAKE_BUILD_WITH_CMAKE
int uv_process_ptr::spawn(uv_loop_t& loop, uv_process_options_t const& options,
void* data)
{
@@ -191,6 +230,7 @@ int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat)
return uv_timer_start(*this, cb, timeout, repeat);
}
+#ifdef CMAKE_BUILD_WITH_CMAKE
uv_tty_ptr::operator uv_stream_t*() const
{
return reinterpret_cast<uv_stream_t*>(handle.get());
@@ -215,13 +255,13 @@ UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(pipe)
UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(stream)
-#ifdef CMAKE_BUILD_WITH_CMAKE
-UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(async)
-
UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(process)
UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(timer)
+#ifdef CMAKE_BUILD_WITH_CMAKE
+UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(async)
+
UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(tty)
#endif
}
diff --git a/Source/cmUVHandlePtr.h b/Source/cmUVHandlePtr.h
index 992c429b1..c09e4bfdf 100644
--- a/Source/cmUVHandlePtr.h
+++ b/Source/cmUVHandlePtr.h
@@ -30,7 +30,45 @@
namespace cm {
/***
- * RAII class to simplify and insure the safe usage of uv_*_t types. This
+ * RAII class to simplify and ensure the safe usage of uv_loop_t. This includes
+ * making sure resources are properly freed.
+ */
+class uv_loop_ptr
+{
+protected:
+ std::shared_ptr<uv_loop_t> loop;
+
+public:
+ uv_loop_ptr(uv_loop_ptr const&) = delete;
+ uv_loop_ptr& operator=(uv_loop_ptr const&) = delete;
+ uv_loop_ptr(uv_loop_ptr&&) noexcept;
+ uv_loop_ptr& operator=(uv_loop_ptr&&) noexcept;
+
+ // Dtor and ctor need to be inline defined like this for default ctors and
+ // dtors to work. Some compilers do not like '= default' here.
+ uv_loop_ptr() {} // NOLINT(modernize-use-equals-default)
+ uv_loop_ptr(std::nullptr_t) {}
+ ~uv_loop_ptr() { this->reset(); }
+
+ int init(void* data = nullptr);
+
+ /**
+ * Properly close the handle if needed and sets the inner handle to nullptr
+ */
+ void reset();
+
+ /**
+ * Allow less verbose calling of uv_loop_* functions
+ * @return reinterpreted handle
+ */
+ operator uv_loop_t*();
+
+ uv_loop_t* get() const;
+ uv_loop_t* operator->() const noexcept;
+};
+
+/***
+ * RAII class to simplify and ensure the safe usage of uv_*_t types. This
* includes making sure resources are properly freed and contains casting
* operators which allow for passing into relevant uv_* functions.
*
diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx
new file mode 100644
index 000000000..90ece0bc5
--- /dev/null
+++ b/Source/cmUVProcessChain.cxx
@@ -0,0 +1,395 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmUVProcessChain.h"
+
+#include "cmAlgorithms.h"
+#include "cmGetPipes.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVStreambuf.h"
+#include "cm_uv.h"
+
+#include <assert.h>
+
+#include <iterator>
+#include <memory>
+#include <utility>
+
+struct cmUVProcessChain::InternalData
+{
+ struct BasicStreamData
+ {
+ cmUVStreambuf Streambuf;
+ cm::uv_pipe_ptr BuiltinStream;
+ uv_stdio_container_t Stdio;
+ };
+
+ template <typename IOStream>
+ struct StreamData : public BasicStreamData
+ {
+ StreamData()
+ : BuiltinIOStream(&this->Streambuf)
+ {
+ }
+
+ IOStream BuiltinIOStream;
+
+ IOStream* GetBuiltinStream()
+ {
+ if (this->BuiltinStream.get()) {
+ return &this->BuiltinIOStream;
+ }
+ return nullptr;
+ }
+ };
+
+ struct ProcessData
+ {
+ cmUVProcessChain::InternalData* Data;
+ cm::uv_process_ptr Process;
+ cm::uv_pipe_ptr OutputPipe;
+ bool Finished = false;
+ Status ProcessStatus;
+ };
+
+ const cmUVProcessChainBuilder* Builder = nullptr;
+
+ bool Valid = false;
+
+ cm::uv_loop_ptr Loop;
+
+ StreamData<std::istream> OutputStreamData;
+ StreamData<std::istream> ErrorStreamData;
+
+ unsigned int ProcessesCompleted = 0;
+ std::vector<std::unique_ptr<ProcessData>> Processes;
+
+ bool Prepare(const cmUVProcessChainBuilder* builder);
+ bool AddCommand(const cmUVProcessChainBuilder::ProcessConfiguration& config,
+ bool first, bool last);
+ bool Finish();
+
+ static const Status* GetStatus(const ProcessData& data);
+};
+
+cmUVProcessChainBuilder::cmUVProcessChainBuilder()
+{
+ this->SetNoStream(Stream_INPUT)
+ .SetNoStream(Stream_OUTPUT)
+ .SetNoStream(Stream_ERROR);
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::AddCommand(
+ const std::vector<std::string>& arguments)
+{
+ if (!arguments.empty()) {
+ this->Processes.emplace_back();
+ this->Processes.back().Arguments = arguments;
+ }
+ return *this;
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetNoStream(Stream stdio)
+{
+ switch (stdio) {
+ case Stream_INPUT:
+ case Stream_OUTPUT:
+ case Stream_ERROR: {
+ auto& streamData = this->Stdio[stdio];
+ streamData.Type = None;
+ break;
+ }
+ }
+ return *this;
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetBuiltinStream(
+ Stream stdio)
+{
+ switch (stdio) {
+ case Stream_INPUT:
+ // FIXME
+ break;
+
+ case Stream_OUTPUT:
+ case Stream_ERROR: {
+ auto& streamData = this->Stdio[stdio];
+ streamData.Type = Builtin;
+ break;
+ }
+ }
+ return *this;
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalStream(
+ Stream stdio, int fd)
+{
+ switch (stdio) {
+ case Stream_INPUT:
+ // FIXME
+ break;
+
+ case Stream_OUTPUT:
+ case Stream_ERROR: {
+ auto& streamData = this->Stdio[stdio];
+ streamData.Type = External;
+ streamData.FileDescriptor = fd;
+ break;
+ }
+ }
+ return *this;
+}
+
+cmUVProcessChain cmUVProcessChainBuilder::Start() const
+{
+ cmUVProcessChain chain;
+
+ if (!chain.Data->Prepare(this)) {
+ return chain;
+ }
+
+ for (auto it = this->Processes.begin(); it != this->Processes.end(); ++it) {
+ if (!chain.Data->AddCommand(*it, it == this->Processes.begin(),
+ it == std::prev(this->Processes.end()))) {
+ return chain;
+ }
+ }
+
+ chain.Data->Finish();
+
+ return chain;
+}
+
+const cmUVProcessChain::Status* cmUVProcessChain::InternalData::GetStatus(
+ const cmUVProcessChain::InternalData::ProcessData& data)
+{
+ if (data.Finished) {
+ return &data.ProcessStatus;
+ }
+ return nullptr;
+}
+
+bool cmUVProcessChain::InternalData::Prepare(
+ const cmUVProcessChainBuilder* builder)
+{
+ this->Builder = builder;
+
+ auto const& output =
+ this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT];
+ auto& outputData = this->OutputStreamData;
+ switch (output.Type) {
+ case cmUVProcessChainBuilder::None:
+ outputData.Stdio.flags = UV_IGNORE;
+ break;
+
+ case cmUVProcessChainBuilder::Builtin:
+ outputData.BuiltinStream.init(*this->Loop, 0);
+ outputData.Stdio.flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ outputData.Stdio.data.stream = outputData.BuiltinStream;
+ break;
+
+ case cmUVProcessChainBuilder::External:
+ outputData.Stdio.flags = UV_INHERIT_FD;
+ outputData.Stdio.data.fd = output.FileDescriptor;
+ break;
+ }
+
+ auto const& error =
+ this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR];
+ auto& errorData = this->ErrorStreamData;
+ switch (error.Type) {
+ case cmUVProcessChainBuilder::None:
+ errorData.Stdio.flags = UV_IGNORE;
+ break;
+
+ case cmUVProcessChainBuilder::Builtin: {
+ int pipeFd[2];
+ if (cmGetPipes(pipeFd) < 0) {
+ return false;
+ }
+
+ errorData.BuiltinStream.init(*this->Loop, 0);
+ if (uv_pipe_open(errorData.BuiltinStream, pipeFd[0]) < 0) {
+ return false;
+ }
+ errorData.Stdio.flags = UV_INHERIT_FD;
+ errorData.Stdio.data.fd = pipeFd[1];
+ break;
+ }
+
+ case cmUVProcessChainBuilder::External:
+ errorData.Stdio.flags = UV_INHERIT_FD;
+ errorData.Stdio.data.fd = error.FileDescriptor;
+ break;
+ }
+
+ return true;
+}
+
+bool cmUVProcessChain::InternalData::AddCommand(
+ const cmUVProcessChainBuilder::ProcessConfiguration& config, bool first,
+ bool last)
+{
+ this->Processes.emplace_back(cm::make_unique<ProcessData>());
+ auto& process = *this->Processes.back();
+ process.Data = this;
+
+ auto options = uv_process_options_t();
+
+ // Bounds were checked at add time, first element is guaranteed to exist
+ options.file = config.Arguments[0].c_str();
+
+ std::vector<const char*> arguments;
+ for (auto const& arg : config.Arguments) {
+ arguments.push_back(arg.c_str());
+ }
+ arguments.push_back(nullptr);
+ options.args = const_cast<char**>(arguments.data());
+ options.flags = UV_PROCESS_WINDOWS_HIDE;
+
+ std::array<uv_stdio_container_t, 3> stdio;
+ stdio[0] = uv_stdio_container_t();
+ if (first) {
+ stdio[0].flags = UV_IGNORE;
+ } else {
+ assert(this->Processes.size() >= 2);
+ auto& prev = *this->Processes[this->Processes.size() - 2];
+ stdio[0].flags = UV_INHERIT_STREAM;
+ stdio[0].data.stream = prev.OutputPipe;
+ }
+ if (last) {
+ stdio[1] = this->OutputStreamData.Stdio;
+ } else {
+ if (process.OutputPipe.init(*this->Loop, 0) < 0) {
+ return false;
+ }
+ stdio[1] = uv_stdio_container_t();
+ stdio[1].flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ stdio[1].data.stream = process.OutputPipe;
+ }
+ stdio[2] = this->ErrorStreamData.Stdio;
+
+ options.stdio = stdio.data();
+ options.stdio_count = 3;
+ options.exit_cb = [](uv_process_t* handle, int64_t exitStatus,
+ int termSignal) {
+ auto* processData = static_cast<ProcessData*>(handle->data);
+ processData->Finished = true;
+ processData->ProcessStatus.ExitStatus = exitStatus;
+ processData->ProcessStatus.TermSignal = termSignal;
+ processData->Data->ProcessesCompleted++;
+ };
+
+ return process.Process.spawn(*this->Loop, options, &process) >= 0;
+}
+
+bool cmUVProcessChain::InternalData::Finish()
+{
+ if (this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT].Type ==
+ cmUVProcessChainBuilder::Builtin) {
+ this->OutputStreamData.Streambuf.open(
+ this->OutputStreamData.BuiltinStream);
+ }
+
+ if (this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR].Type ==
+ cmUVProcessChainBuilder::Builtin) {
+ cm::uv_pipe_ptr tmpPipe;
+ if (tmpPipe.init(*this->Loop, 0) < 0) {
+ return false;
+ }
+ if (uv_pipe_open(tmpPipe, this->ErrorStreamData.Stdio.data.fd) < 0) {
+ return false;
+ }
+ tmpPipe.reset();
+
+ this->ErrorStreamData.Streambuf.open(this->ErrorStreamData.BuiltinStream);
+ }
+
+ this->Valid = true;
+ return true;
+}
+
+cmUVProcessChain::cmUVProcessChain()
+ : Data(cm::make_unique<InternalData>())
+{
+ this->Data->Loop.init();
+}
+
+cmUVProcessChain::cmUVProcessChain(cmUVProcessChain&& other) noexcept
+ : Data(std::move(other.Data))
+{
+}
+
+cmUVProcessChain::~cmUVProcessChain() = default;
+
+cmUVProcessChain& cmUVProcessChain::operator=(
+ cmUVProcessChain&& other) noexcept
+{
+ this->Data = std::move(other.Data);
+ return *this;
+}
+
+uv_loop_t& cmUVProcessChain::GetLoop()
+{
+ return *this->Data->Loop;
+}
+
+std::istream* cmUVProcessChain::OutputStream()
+{
+ return this->Data->OutputStreamData.GetBuiltinStream();
+}
+
+std::istream* cmUVProcessChain::ErrorStream()
+{
+ return this->Data->ErrorStreamData.GetBuiltinStream();
+}
+
+bool cmUVProcessChain::Valid() const
+{
+ return this->Data->Valid;
+}
+
+bool cmUVProcessChain::Wait(int64_t milliseconds)
+{
+ bool timeout = false;
+ cm::uv_timer_ptr timer;
+
+ if (milliseconds >= 0) {
+ timer.init(*this->Data->Loop, &timeout);
+ timer.start(
+ [](uv_timer_t* handle) {
+ auto* timeoutPtr = static_cast<bool*>(handle->data);
+ *timeoutPtr = true;
+ },
+ milliseconds, 0);
+ }
+
+ while (!timeout &&
+ this->Data->ProcessesCompleted < this->Data->Processes.size()) {
+ uv_run(this->Data->Loop, UV_RUN_ONCE);
+ }
+
+ return !timeout;
+}
+
+std::vector<const cmUVProcessChain::Status*> cmUVProcessChain::GetStatus()
+ const
+{
+ std::vector<const cmUVProcessChain::Status*> statuses(
+ this->Data->Processes.size(), nullptr);
+ for (std::size_t i = 0; i < statuses.size(); i++) {
+ statuses[i] = this->GetStatus(i);
+ }
+ return statuses;
+}
+
+const cmUVProcessChain::Status* cmUVProcessChain::GetStatus(
+ std::size_t index) const
+{
+ auto const& process = *this->Data->Processes[index];
+ if (process.Finished) {
+ return &process.ProcessStatus;
+ }
+ return nullptr;
+}
diff --git a/Source/cmUVProcessChain.h b/Source/cmUVProcessChain.h
new file mode 100644
index 000000000..2b3352070
--- /dev/null
+++ b/Source/cmUVProcessChain.h
@@ -0,0 +1,100 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmUVProcessChain_h
+#define cmUVProcessChain_h
+
+#include "cm_uv.h"
+
+#include <array>
+#include <iosfwd>
+#include <memory> // IWYU pragma: keep
+#include <string>
+#include <vector>
+
+#include <stdint.h>
+
+class cmUVProcessChain;
+
+class cmUVProcessChainBuilder
+{
+public:
+ enum Stream
+ {
+ Stream_INPUT = 0,
+ Stream_OUTPUT = 1,
+ Stream_ERROR = 2,
+ };
+
+ cmUVProcessChainBuilder();
+
+ cmUVProcessChainBuilder& AddCommand(
+ const std::vector<std::string>& arguments);
+ cmUVProcessChainBuilder& SetNoStream(Stream stdio);
+ cmUVProcessChainBuilder& SetBuiltinStream(Stream stdio);
+ cmUVProcessChainBuilder& SetExternalStream(Stream stdio, int fd);
+
+ cmUVProcessChain Start() const;
+
+private:
+ enum StdioType
+ {
+ None,
+ Builtin,
+ External,
+ };
+
+ friend class cmUVProcessChain;
+
+ struct StdioConfiguration
+ {
+ StdioType Type;
+ int FileDescriptor;
+ };
+
+ struct ProcessConfiguration
+ {
+ std::vector<std::string> Arguments;
+ };
+
+ std::array<StdioConfiguration, 3> Stdio;
+ std::vector<ProcessConfiguration> Processes;
+};
+
+class cmUVProcessChain
+{
+public:
+ struct Status
+ {
+ int64_t ExitStatus;
+ int TermSignal;
+ };
+
+ cmUVProcessChain(const cmUVProcessChain& other) = delete;
+ cmUVProcessChain(cmUVProcessChain&& other) noexcept;
+
+ ~cmUVProcessChain();
+
+ cmUVProcessChain& operator=(const cmUVProcessChain& other) = delete;
+ cmUVProcessChain& operator=(cmUVProcessChain&& other) noexcept;
+
+ uv_loop_t& GetLoop();
+
+ // FIXME: Add stdin support
+ std::istream* OutputStream();
+ std::istream* ErrorStream();
+
+ bool Valid() const;
+ bool Wait(int64_t milliseconds = -1);
+ std::vector<const Status*> GetStatus() const;
+ const Status* GetStatus(std::size_t index) const;
+
+private:
+ friend class cmUVProcessChainBuilder;
+
+ cmUVProcessChain();
+
+ struct InternalData;
+ std::unique_ptr<InternalData> Data;
+};
+
+#endif
diff --git a/Source/cmUVStreambuf.h b/Source/cmUVStreambuf.h
new file mode 100644
index 000000000..873352b1a
--- /dev/null
+++ b/Source/cmUVStreambuf.h
@@ -0,0 +1,219 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmUVStreambuf_h
+#define cmUVStreambuf_h
+
+#include "cmUVHandlePtr.h"
+
+#include "cm_uv.h"
+
+#include <algorithm>
+#include <cstring>
+#include <streambuf>
+#include <vector>
+
+/*
+ * This file is based on example code from:
+ *
+ * http://www.voidcn.com/article/p-vjnlygmc-gy.html
+ *
+ * The example code was distributed under the following license:
+ *
+ * Copyright 2007 Edd Dawson.
+ * Distributed under the Boost Software License, Version 1.0.
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+template <typename CharT, typename Traits = std::char_traits<CharT>>
+class cmBasicUVStreambuf : public std::basic_streambuf<CharT, Traits>
+{
+public:
+ cmBasicUVStreambuf(std::size_t bufSize = 256, std::size_t putBack = 8);
+ ~cmBasicUVStreambuf() override;
+
+ bool is_open() const;
+
+ cmBasicUVStreambuf* open(uv_stream_t* stream);
+
+ cmBasicUVStreambuf* close();
+
+protected:
+ typename cmBasicUVStreambuf::int_type underflow() override;
+ std::streamsize showmanyc() override;
+
+ // FIXME: Add write support
+
+private:
+ uv_stream_t* Stream = nullptr;
+ void* OldStreamData = nullptr;
+ const std::size_t PutBack = 0;
+ std::vector<CharT> InputBuffer;
+ bool EndOfFile = false;
+
+ void StreamReadStartStop();
+
+ void StreamRead(ssize_t nread);
+ void HandleAlloc(uv_buf_t* buf);
+};
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>::cmBasicUVStreambuf(std::size_t bufSize,
+ std::size_t putBack)
+ : PutBack(std::max<std::size_t>(putBack, 1))
+ , InputBuffer(std::max<std::size_t>(this->PutBack, bufSize) + this->PutBack)
+{
+ this->close();
+}
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>::~cmBasicUVStreambuf()
+{
+ this->close();
+}
+
+template <typename CharT, typename Traits>
+bool cmBasicUVStreambuf<CharT, Traits>::is_open() const
+{
+ return this->Stream != nullptr;
+}
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>* cmBasicUVStreambuf<CharT, Traits>::open(
+ uv_stream_t* stream)
+{
+ this->close();
+ this->Stream = stream;
+ this->EndOfFile = false;
+ if (this->Stream) {
+ this->OldStreamData = this->Stream->data;
+ this->Stream->data = this;
+ }
+ this->StreamReadStartStop();
+ return this;
+}
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>* cmBasicUVStreambuf<CharT, Traits>::close()
+{
+ if (this->Stream) {
+ uv_read_stop(this->Stream);
+ this->Stream->data = this->OldStreamData;
+ }
+ this->Stream = nullptr;
+ CharT* readEnd = this->InputBuffer.data() + this->InputBuffer.size();
+ this->setg(readEnd, readEnd, readEnd);
+ return this;
+}
+
+template <typename CharT, typename Traits>
+typename cmBasicUVStreambuf<CharT, Traits>::int_type
+cmBasicUVStreambuf<CharT, Traits>::underflow()
+{
+ if (!this->is_open()) {
+ return Traits::eof();
+ }
+
+ if (this->gptr() < this->egptr()) {
+ return Traits::to_int_type(*this->gptr());
+ }
+
+ this->StreamReadStartStop();
+ while (this->in_avail() == 0) {
+ uv_run(this->Stream->loop, UV_RUN_ONCE);
+ }
+ if (this->in_avail() == -1) {
+ return Traits::eof();
+ }
+ return Traits::to_int_type(*this->gptr());
+}
+
+template <typename CharT, typename Traits>
+std::streamsize cmBasicUVStreambuf<CharT, Traits>::showmanyc()
+{
+ if (!this->is_open() || this->EndOfFile) {
+ return -1;
+ }
+ return 0;
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVStreambuf<CharT, Traits>::StreamReadStartStop()
+{
+ if (this->Stream) {
+ uv_read_stop(this->Stream);
+ if (this->gptr() >= this->egptr()) {
+ uv_read_start(
+ this->Stream,
+ [](uv_handle_t* handle, size_t /* unused */, uv_buf_t* buf) {
+ auto streambuf =
+ static_cast<cmBasicUVStreambuf<CharT, Traits>*>(handle->data);
+ streambuf->HandleAlloc(buf);
+ },
+ [](uv_stream_t* stream2, ssize_t nread, const uv_buf_t* /* unused */) {
+ auto streambuf =
+ static_cast<cmBasicUVStreambuf<CharT, Traits>*>(stream2->data);
+ streambuf->StreamRead(nread);
+ });
+ }
+ }
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVStreambuf<CharT, Traits>::HandleAlloc(uv_buf_t* buf)
+{
+ auto size = this->egptr() - this->gptr();
+ std::memmove(this->InputBuffer.data(), this->gptr(),
+ this->egptr() - this->gptr());
+ this->setg(this->InputBuffer.data(), this->InputBuffer.data(),
+ this->InputBuffer.data() + size);
+ buf->base = this->egptr();
+#ifdef _WIN32
+# define BUF_LEN_TYPE ULONG
+#else
+# define BUF_LEN_TYPE size_t
+#endif
+ buf->len = BUF_LEN_TYPE(
+ (this->InputBuffer.data() + this->InputBuffer.size() - this->egptr()) *
+ sizeof(CharT));
+#undef BUF_LEN_TYPE
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVStreambuf<CharT, Traits>::StreamRead(ssize_t nread)
+{
+ if (nread > 0) {
+ this->setg(this->eback(), this->gptr(),
+ this->egptr() + nread / sizeof(CharT));
+ uv_read_stop(this->Stream);
+ } else if (nread < 0 /*|| nread == UV_EOF*/) {
+ this->EndOfFile = true;
+ uv_read_stop(this->Stream);
+ }
+}
+
+using cmUVStreambuf = cmBasicUVStreambuf<char>;
+
+#endif
diff --git a/Source/cmUseMangledMesaCommand.cxx b/Source/cmUseMangledMesaCommand.cxx
index 9648b21d8..43581947c 100644
--- a/Source/cmUseMangledMesaCommand.cxx
+++ b/Source/cmUseMangledMesaCommand.cxx
@@ -19,7 +19,7 @@ bool cmUseMangledMesaCommand::InitialPass(std::vector<std::string> const& args,
this->SetError("called with incorrect number of arguments");
return false;
}
- const char* inputDir = args[0].c_str();
+ const std::string& inputDir = args[0];
std::string glh = inputDir;
glh += "/";
glh += "gl.h";
@@ -30,11 +30,11 @@ bool cmUseMangledMesaCommand::InitialPass(std::vector<std::string> const& args,
this->SetError(e);
return false;
}
- const char* destDir = args[1].c_str();
+ const std::string& destDir = args[1];
std::vector<std::string> files;
cmSystemTools::Glob(inputDir, "\\.h$", files);
if (files.empty()) {
- cmSystemTools::Error("Could not open Mesa Directory ", inputDir);
+ cmSystemTools::Error("Could not open Mesa Directory " + inputDir);
return false;
}
cmSystemTools::MakeDirectory(destDir);
@@ -42,14 +42,14 @@ bool cmUseMangledMesaCommand::InitialPass(std::vector<std::string> const& args,
std::string path = inputDir;
path += "/";
path += f;
- this->CopyAndFullPathMesaHeader(path.c_str(), destDir);
+ this->CopyAndFullPathMesaHeader(path, destDir);
}
return true;
}
-void cmUseMangledMesaCommand::CopyAndFullPathMesaHeader(const char* source,
- const char* outdir)
+void cmUseMangledMesaCommand::CopyAndFullPathMesaHeader(
+ const std::string& source, const std::string& outdir)
{
std::string dir, file;
cmSystemTools::SplitProgramPath(source, dir, file);
@@ -60,14 +60,14 @@ void cmUseMangledMesaCommand::CopyAndFullPathMesaHeader(const char* source,
tempOutputFile += ".tmp";
cmsys::ofstream fout(tempOutputFile.c_str());
if (!fout) {
- cmSystemTools::Error("Could not open file for write in copy operation: ",
- tempOutputFile.c_str(), outdir);
+ cmSystemTools::Error("Could not open file for write in copy operation: " +
+ tempOutputFile + outdir);
cmSystemTools::ReportLastSystemError("");
return;
}
- cmsys::ifstream fin(source);
+ cmsys::ifstream fin(source.c_str());
if (!fin) {
- cmSystemTools::Error("Could not open file for read in copy operation",
+ cmSystemTools::Error("Could not open file for read in copy operation" +
source);
return;
}
@@ -78,7 +78,7 @@ void cmUseMangledMesaCommand::CopyAndFullPathMesaHeader(const char* source,
cmsys::RegularExpression includeLine(
"^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)[\">]");
// regular expression for gl/ or GL/ in a file (match(1) of above)
- cmsys::RegularExpression glDirLine("(gl|GL)(/|\\\\)([^<\"]+)");
+ cmsys::RegularExpression glDirLine(R"((gl|GL)(/|\\)([^<"]+))");
// regular expression for gl GL or xmesa in a file (match(1) of above)
cmsys::RegularExpression glLine("(gl|GL|xmesa)");
while (cmSystemTools::GetLineFromStream(fin, inLine)) {
diff --git a/Source/cmUseMangledMesaCommand.h b/Source/cmUseMangledMesaCommand.h
index 78f86167b..e2f1d9b90 100644
--- a/Source/cmUseMangledMesaCommand.h
+++ b/Source/cmUseMangledMesaCommand.h
@@ -20,7 +20,8 @@ public:
cmExecutionStatus& status) override;
protected:
- void CopyAndFullPathMesaHeader(const char* source, const char* outdir);
+ void CopyAndFullPathMesaHeader(const std::string& source,
+ const std::string& outdir);
};
#endif
diff --git a/Source/cmUtilitySourceCommand.cxx b/Source/cmUtilitySourceCommand.cxx
index 231bca41d..b59a587cd 100644
--- a/Source/cmUtilitySourceCommand.cxx
+++ b/Source/cmUtilitySourceCommand.cxx
@@ -79,7 +79,7 @@ bool cmUtilitySourceCommand::InitialPass(std::vector<std::string> const& args,
}
// The source exists.
- std::string cmakeCFGout =
+ const std::string& cmakeCFGout =
this->Makefile->GetRequiredDefinition("CMAKE_CFG_INTDIR");
std::string utilityDirectory = this->Makefile->GetCurrentBinaryDirectory();
std::string exePath;
diff --git a/Source/cmUuid.cxx b/Source/cmUuid.cxx
index 201e1ccef..51ecbd180 100644
--- a/Source/cmUuid.cxx
+++ b/Source/cmUuid.cxx
@@ -4,16 +4,10 @@
#include "cmCryptoHash.h"
+#include <array>
#include <string.h>
-cmUuid::cmUuid()
-{
- Groups.push_back(4);
- Groups.push_back(2);
- Groups.push_back(2);
- Groups.push_back(2);
- Groups.push_back(6);
-}
+static const std::array<int, 5> kUuidGroups = { { 4, 2, 2, 2, 6 } };
std::string cmUuid::FromMd5(std::vector<unsigned char> const& uuidNamespace,
std::string const& name) const
@@ -83,11 +77,11 @@ bool cmUuid::StringToBinary(std::string const& input,
return false;
}
size_t index = 0;
- for (size_t i = 0; i < this->Groups.size(); ++i) {
+ for (size_t i = 0; i < kUuidGroups.size(); ++i) {
if (i != 0 && input[index++] != '-') {
return false;
}
- size_t digits = this->Groups[i] * 2;
+ size_t digits = kUuidGroups[i] * 2;
if (!StringToBinaryImpl(input.substr(index, digits), output)) {
return false;
}
@@ -103,12 +97,12 @@ std::string cmUuid::BinaryToString(const unsigned char* input) const
std::string output;
size_t inputIndex = 0;
- for (size_t i = 0; i < this->Groups.size(); ++i) {
+ for (size_t i = 0; i < kUuidGroups.size(); ++i) {
if (i != 0) {
output += '-';
}
- size_t bytes = this->Groups[i];
+ size_t bytes = kUuidGroups[i];
for (size_t j = 0; j < bytes; ++j) {
unsigned char byte = input[inputIndex++];
output += this->ByteToHex(byte);
diff --git a/Source/cmUuid.h b/Source/cmUuid.h
index 158ce6ee4..7de20dd29 100644
--- a/Source/cmUuid.h
+++ b/Source/cmUuid.h
@@ -15,8 +15,6 @@
class cmUuid
{
public:
- cmUuid();
-
std::string FromMd5(std::vector<unsigned char> const& uuidNamespace,
std::string const& name) const;
@@ -42,8 +40,6 @@ private:
std::string BinaryToString(const unsigned char* input) const;
bool IntFromHexDigit(char input, char& output) const;
-
- std::vector<int> Groups;
};
#endif
diff --git a/Source/cmVariableWatch.h b/Source/cmVariableWatch.h
index 5855fed29..123010179 100644
--- a/Source/cmVariableWatch.h
+++ b/Source/cmVariableWatch.h
@@ -72,6 +72,9 @@ protected:
this->DeleteDataCall(this->ClientData);
}
}
+ Pair() = default;
+ Pair(const Pair&) = delete;
+ Pair& operator=(const Pair&) = delete;
};
typedef std::vector<std::shared_ptr<Pair>> VectorOfPairs;
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index f2f5e3f63..ee5f9b4d0 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -4,11 +4,13 @@
#include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h"
+#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalVisualStudio10Generator.h"
+#include "cmLinkLineDeviceComputer.h"
#include "cmLocalVisualStudio10Generator.h"
#include "cmMakefile.h"
#include "cmSourceFile.h"
@@ -624,8 +626,8 @@ void cmVisualStudio10TargetGenerator::Generate()
propsLocal += this->DefaultArtifactDir;
propsLocal += "\\nasm.props";
ConvertToWindowsSlash(propsLocal);
- this->Makefile->ConfigureFile(propsTemplate.c_str(),
- propsLocal.c_str(), false, true, true);
+ this->Makefile->ConfigureFile(propsTemplate, propsLocal, false, true,
+ true);
Elem(e1, "Import").Attribute("Project", propsLocal);
}
}
@@ -663,6 +665,8 @@ void cmVisualStudio10TargetGenerator::Generate()
this->WriteCustomCommands(e0);
this->WriteAllSources(e0);
this->WriteDotNetReferences(e0);
+ this->WritePackageReferences(e0);
+ this->WriteImports(e0);
this->WriteEmbeddedResourceGroup(e0);
this->WriteXamlFilesGroup(e0);
this->WriteWinRTReferences(e0);
@@ -735,6 +739,33 @@ void cmVisualStudio10TargetGenerator::Generate()
this->WriteGroups();
}
+void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0)
+{
+ std::vector<std::string> packageReferences;
+ if (const char* vsPackageReferences =
+ this->GeneratorTarget->GetProperty("VS_PACKAGE_REFERENCES")) {
+ cmSystemTools::ExpandListArgument(vsPackageReferences, packageReferences);
+ }
+ if (!packageReferences.empty()) {
+ Elem e1(e0, "ItemGroup");
+ for (std::string const& ri : packageReferences) {
+ size_t versionIndex = ri.find_last_of('_');
+ if (versionIndex != std::string::npos) {
+ WritePackageReference(e1, ri.substr(0, versionIndex),
+ ri.substr(versionIndex + 1));
+ }
+ }
+ }
+}
+
+void cmVisualStudio10TargetGenerator::WritePackageReference(
+ Elem& e1, std::string const& ref, std::string const& version)
+{
+ Elem e2(e1, "PackageReference");
+ e2.Attribute("Include", ref);
+ e2.Attribute("Version", version);
+}
+
void cmVisualStudio10TargetGenerator::WriteDotNetReferences(Elem& e0)
{
std::vector<std::string> references;
@@ -811,6 +842,24 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReference(
this->WriteDotNetReferenceCustomTags(e2, ref);
}
+void cmVisualStudio10TargetGenerator::WriteImports(Elem& e0)
+{
+ const char* imports =
+ this->GeneratorTarget->Target->GetProperty("VS_PROJECT_IMPORT");
+ if (imports) {
+ std::vector<std::string> argsSplit;
+ cmSystemTools::ExpandListArgument(std::string(imports), argsSplit, false);
+ for (auto& path : argsSplit) {
+ if (!cmsys::SystemTools::FileIsFullPath(path)) {
+ path = this->Makefile->GetCurrentSourceDirectory() + "/" + path;
+ }
+ ConvertToWindowsSlash(path);
+ Elem e1(e0, "Import");
+ e1.Attribute("Project", path);
+ }
+ }
+}
+
void cmVisualStudio10TargetGenerator::WriteDotNetReferenceCustomTags(
Elem& e2, std::string const& ref)
{
@@ -1164,7 +1213,7 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues(
this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) {
e1.Element("CharacterSet", "Unicode");
} else if (this->GeneratorTarget->GetType() <=
- cmStateEnums::MODULE_LIBRARY &&
+ cmStateEnums::OBJECT_LIBRARY &&
this->ClOptions[config]->UsingSBCS()) {
e1.Element("CharacterSet", "NotSet");
} else {
@@ -1323,8 +1372,7 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule(
std::string error = "Could not create file: [";
error += sourcePath;
error += "] ";
- cmSystemTools::Error(error.c_str(),
- cmSystemTools::GetLastSystemError().c_str());
+ cmSystemTools::Error(error + cmSystemTools::GetLastSystemError());
}
}
}
@@ -1454,10 +1502,10 @@ std::string cmVisualStudio10TargetGenerator::ConvertPath(
static void ConvertToWindowsSlash(std::string& s)
{
// first convert all of the slashes
- std::string::size_type pos = 0;
- while ((pos = s.find('/', pos)) != std::string::npos) {
- s[pos] = '\\';
- pos++;
+ for (auto& ch : s) {
+ if (ch == '/') {
+ ch = '\\';
+ }
}
}
@@ -1473,7 +1521,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
std::vector<cmGeneratorTarget::AllConfigSource> const& sources =
this->GeneratorTarget->GetAllConfigSources();
- std::set<cmSourceGroup*> groupsUsed;
+ std::set<cmSourceGroup const*> groupsUsed;
for (cmGeneratorTarget::AllConfigSource const& si : sources) {
std::string const& source = si.Source->GetFullPath();
cmSourceGroup* sourceGroup =
@@ -1558,13 +1606,13 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
{
Elem e1(e0, "ItemGroup");
e1.SetHasElements();
- std::vector<cmSourceGroup*> groupsVec(groupsUsed.begin(),
- groupsUsed.end());
+ std::vector<cmSourceGroup const*> groupsVec(groupsUsed.begin(),
+ groupsUsed.end());
std::sort(groupsVec.begin(), groupsVec.end(),
- [](cmSourceGroup* l, cmSourceGroup* r) {
+ [](cmSourceGroup const* l, cmSourceGroup const* r) {
return l->GetFullName() < r->GetFullName();
});
- for (cmSourceGroup* sg : groupsVec) {
+ for (cmSourceGroup const* sg : groupsVec) {
std::string const& name = sg->GetFullName();
if (!name.empty()) {
std::string guidName = "SG_Filter_" + name;
@@ -1596,7 +1644,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
// Add to groupsUsed empty source groups that have non-empty children.
void cmVisualStudio10TargetGenerator::AddMissingSourceGroups(
- std::set<cmSourceGroup*>& groupsUsed,
+ std::set<cmSourceGroup const*>& groupsUsed,
const std::vector<cmSourceGroup>& allGroups)
{
for (cmSourceGroup const& current : allGroups) {
@@ -1607,17 +1655,15 @@ void cmVisualStudio10TargetGenerator::AddMissingSourceGroups(
this->AddMissingSourceGroups(groupsUsed, children);
- cmSourceGroup* current_ptr = const_cast<cmSourceGroup*>(&current);
- if (groupsUsed.find(current_ptr) != groupsUsed.end()) {
+ if (groupsUsed.count(&current) > 0) {
continue; // group has already been added to set
}
// check if it least one of the group's descendants is not empty
// (at least one child must already have been added)
- std::vector<cmSourceGroup>::const_iterator child_it = children.begin();
+ auto child_it = children.begin();
while (child_it != children.end()) {
- cmSourceGroup* child_ptr = const_cast<cmSourceGroup*>(&(*child_it));
- if (groupsUsed.find(child_ptr) != groupsUsed.end()) {
+ if (groupsUsed.count(&(*child_it)) > 0) {
break; // found a child that was already added => add current group too
}
child_it++;
@@ -1627,7 +1673,7 @@ void cmVisualStudio10TargetGenerator::AddMissingSourceGroups(
continue; // no descendants have source files => ignore this group
}
- groupsUsed.insert(current_ptr);
+ groupsUsed.insert(&current);
}
}
@@ -2539,8 +2585,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
this->GeneratorTarget->GetLinkerLanguage(configName);
if (linkLanguage.empty()) {
cmSystemTools::Error(
- "CMake can not determine linker language for target: ",
- this->Name.c_str());
+ "CMake can not determine linker language for target: " + this->Name);
return false;
}
@@ -2555,24 +2600,17 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
} else {
std::set<std::string> languages;
this->GeneratorTarget->GetLanguages(languages, configName);
- for (const char* const* l = cm::cbegin(clLangs); l != cm::cend(clLangs);
- ++l) {
- if (languages.find(*l) != languages.end()) {
- langForClCompile = *l;
+ for (const char* l : clLangs) {
+ if (languages.count(l)) {
+ langForClCompile = l;
break;
}
}
}
this->LangForClCompile = langForClCompile;
if (!langForClCompile.empty()) {
- std::string baseFlagVar = "CMAKE_";
- baseFlagVar += langForClCompile;
- baseFlagVar += "_FLAGS";
- flags = this->Makefile->GetRequiredDefinition(baseFlagVar);
- std::string flagVar =
- baseFlagVar + "_" + cmSystemTools::UpperCase(configName);
- flags += " ";
- flags += this->Makefile->GetRequiredDefinition(flagVar);
+ this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+ langForClCompile, configName);
this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
langForClCompile, configName);
}
@@ -2872,10 +2910,9 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
Options& cudaOptions = *pOptions;
// Get compile flags for CUDA in this directory.
- std::string CONFIG = cmSystemTools::UpperCase(configName);
- std::string configFlagsVar = std::string("CMAKE_CUDA_FLAGS_") + CONFIG;
- std::string flags = this->Makefile->GetSafeDefinition("CMAKE_CUDA_FLAGS") +
- " " + this->Makefile->GetSafeDefinition(configFlagsVar);
+ std::string flags;
+ this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, "CUDA",
+ configName);
this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, "CUDA",
configName);
@@ -3022,21 +3059,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions(
Options& cudaLinkOptions = *pOptions;
// Determine if we need to do a device link
- bool doDeviceLinking = false;
- if (const char* resolveDeviceSymbols =
- this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
- doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
- } else {
- switch (this->GeneratorTarget->GetType()) {
- case cmStateEnums::SHARED_LIBRARY:
- case cmStateEnums::MODULE_LIBRARY:
- case cmStateEnums::EXECUTABLE:
- doDeviceLinking = true;
- break;
- default:
- break;
- }
- }
+ const bool doDeviceLinking = requireDeviceLinking(
+ *this->GeneratorTarget, *this->LocalGenerator, configName);
cudaLinkOptions.AddFlag("PerformDeviceLink",
doDeviceLinking ? "true" : "false");
@@ -3089,11 +3113,9 @@ bool cmVisualStudio10TargetGenerator::ComputeMasmOptions(
this->LocalGenerator, Options::MasmCompiler, gg->GetMasmFlagTable());
Options& masmOptions = *pOptions;
- std::string CONFIG = cmSystemTools::UpperCase(configName);
- std::string configFlagsVar = std::string("CMAKE_ASM_MASM_FLAGS_") + CONFIG;
- std::string flags =
- this->Makefile->GetSafeDefinition("CMAKE_ASM_MASM_FLAGS") + " " +
- this->Makefile->GetSafeDefinition(configFlagsVar);
+ std::string flags;
+ this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+ "ASM_MASM", configName);
masmOptions.Parse(flags);
@@ -3143,12 +3165,11 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions(
this->LocalGenerator, Options::NasmCompiler, gg->GetNasmFlagTable());
Options& nasmOptions = *pOptions;
- std::string CONFIG = cmSystemTools::UpperCase(configName);
- std::string configFlagsVar = "CMAKE_ASM_NASM_FLAGS_" + CONFIG;
- std::string flags =
- this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_FLAGS") + " -f" +
- this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_OBJECT_FORMAT") + " " +
- this->Makefile->GetSafeDefinition(configFlagsVar);
+ std::string flags;
+ this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+ "ASM_NASM", configName);
+ flags += " -f";
+ flags += this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_OBJECT_FORMAT");
nasmOptions.Parse(flags);
// Get includes for this target
@@ -3370,8 +3391,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
const std::string& linkLanguage = linkClosure->LinkerLanguage;
if (linkLanguage.empty()) {
cmSystemTools::Error(
- "CMake can not determine linker language for target: ",
- this->Name.c_str());
+ "CMake can not determine linker language for target: " + this->Name);
return false;
}
@@ -3416,8 +3436,8 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
this->GeneratorTarget->GetLinkInformation(config);
if (!pcli) {
cmSystemTools::Error(
- "CMake can not compute cmComputeLinkInformation for target: ",
- this->Name.c_str());
+ "CMake can not compute cmComputeLinkInformation for target: " +
+ this->Name);
return false;
}
cmComputeLinkInformation& cli = *pcli;
@@ -3444,7 +3464,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
std::string standardLibsVar = "CMAKE_";
standardLibsVar += linkLanguage;
standardLibsVar += "_STANDARD_LIBRARIES";
- std::string const libs = this->Makefile->GetSafeDefinition(standardLibsVar);
+ std::string const& libs = this->Makefile->GetSafeDefinition(standardLibsVar);
cmSystemTools::ParseWindowsCommandLine(libs.c_str(), libVec);
linkOptions.AddFlag("AdditionalDependencies", libVec);
@@ -3464,18 +3484,11 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
linkDirs.push_back("%(AdditionalLibraryDirectories)");
linkOptions.AddFlag("AdditionalLibraryDirectories", linkDirs);
- std::string targetName;
- std::string targetNameSO;
- std::string targetNameFull;
- std::string targetNameImport;
- std::string targetNamePDB;
+ cmGeneratorTarget::Names targetNames;
if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
- this->GeneratorTarget->GetExecutableNames(
- targetName, targetNameFull, targetNameImport, targetNamePDB, config);
+ targetNames = this->GeneratorTarget->GetExecutableNames(config);
} else {
- this->GeneratorTarget->GetLibraryNames(targetName, targetNameSO,
- targetNameFull, targetNameImport,
- targetNamePDB, config);
+ targetNames = this->GeneratorTarget->GetLibraryNames(config);
}
if (this->MSTools) {
@@ -3516,11 +3529,11 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
std::string pdb = this->GeneratorTarget->GetPDBDirectory(config);
pdb += "/";
- pdb += targetNamePDB;
+ pdb += targetNames.PDB;
std::string imLib = this->GeneratorTarget->GetDirectory(
config, cmStateEnums::ImportLibraryArtifact);
imLib += "/";
- imLib += targetNameImport;
+ imLib += targetNames.ImportLibrary;
linkOptions.AddFlag("ImportLibrary", imLib);
linkOptions.AddFlag("ProgramDataBaseFile", pdb);
@@ -3544,7 +3557,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
linkOptions.AppendFlag("IgnoreSpecificDefaultLibraries", "ole32.lib");
}
} else if (this->NsightTegra) {
- linkOptions.AddFlag("SoName", targetNameSO);
+ linkOptions.AddFlag("SoName", targetNames.SharedObject);
}
linkOptions.Parse(flags);
@@ -3604,8 +3617,8 @@ bool cmVisualStudio10TargetGenerator::ComputeLibOptions(
this->GeneratorTarget->GetLinkInformation(config);
if (!pcli) {
cmSystemTools::Error(
- "CMake can not compute cmComputeLinkInformation for target: ",
- this->Name.c_str());
+ "CMake can not compute cmComputeLinkInformation for target: " +
+ this->Name);
return false;
}
@@ -4097,10 +4110,7 @@ bool cmVisualStudio10TargetGenerator::IsResxHeader(
{
std::set<std::string> expectedResxHeaders;
this->GeneratorTarget->GetExpectedResxHeaders(expectedResxHeaders, "");
-
- std::set<std::string>::const_iterator it =
- expectedResxHeaders.find(headerFile);
- return it != expectedResxHeaders.end();
+ return expectedResxHeaders.count(headerFile) > 0;
}
bool cmVisualStudio10TargetGenerator::IsXamlHeader(
@@ -4108,10 +4118,7 @@ bool cmVisualStudio10TargetGenerator::IsXamlHeader(
{
std::set<std::string> expectedXamlHeaders;
this->GeneratorTarget->GetExpectedXamlHeaders(expectedXamlHeaders, "");
-
- std::set<std::string>::const_iterator it =
- expectedXamlHeaders.find(headerFile);
- return it != expectedXamlHeaders.end();
+ return expectedXamlHeaders.count(headerFile) > 0;
}
bool cmVisualStudio10TargetGenerator::IsXamlSource(
@@ -4119,10 +4126,7 @@ bool cmVisualStudio10TargetGenerator::IsXamlSource(
{
std::set<std::string> expectedXamlSources;
this->GeneratorTarget->GetExpectedXamlSources(expectedXamlSources, "");
-
- std::set<std::string>::const_iterator it =
- expectedXamlSources.find(sourceFile);
- return it != expectedXamlSources.end();
+ return expectedXamlSources.count(sourceFile) > 0;
}
void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings(Elem& e1)
@@ -4131,29 +4135,29 @@ void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings(Elem& e1)
bool isAppContainer = false;
bool const isWindowsPhone = this->GlobalGenerator->TargetsWindowsPhone();
bool const isWindowsStore = this->GlobalGenerator->TargetsWindowsStore();
- std::string const& v = this->GlobalGenerator->GetSystemVersion();
+ std::string const& rev = this->GlobalGenerator->GetApplicationTypeRevision();
if (isWindowsPhone || isWindowsStore) {
e1.Element("ApplicationType",
(isWindowsPhone ? "Windows Phone" : "Windows Store"));
e1.Element("DefaultLanguage", "en-US");
- if (cmHasLiteralPrefix(v, "10.0")) {
- e1.Element("ApplicationTypeRevision", "10.0");
+ if (rev == "10.0") {
+ e1.Element("ApplicationTypeRevision", rev);
// Visual Studio 14.0 is necessary for building 10.0 apps
e1.Element("MinimumVisualStudioVersion", "14.0");
if (this->GeneratorTarget->GetType() < cmStateEnums::UTILITY) {
isAppContainer = true;
}
- } else if (v == "8.1") {
- e1.Element("ApplicationTypeRevision", v);
+ } else if (rev == "8.1") {
+ e1.Element("ApplicationTypeRevision", rev);
// Visual Studio 12.0 is necessary for building 8.1 apps
e1.Element("MinimumVisualStudioVersion", "12.0");
if (this->GeneratorTarget->GetType() < cmStateEnums::UTILITY) {
isAppContainer = true;
}
- } else if (v == "8.0") {
- e1.Element("ApplicationTypeRevision", v);
+ } else if (rev == "8.0") {
+ e1.Element("ApplicationTypeRevision", rev);
// Visual Studio 11.0 is necessary for building 8.0 apps
e1.Element("MinimumVisualStudioVersion", "11.0");
@@ -4185,7 +4189,7 @@ void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings(Elem& e1)
"VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION");
if (targetPlatformMinVersion) {
e1.Element("WindowsTargetPlatformMinVersion", targetPlatformMinVersion);
- } else if (isWindowsStore && cmHasLiteralPrefix(v, "10.0")) {
+ } else if (isWindowsStore && rev == "10.0") {
// If the min version is not set, then use the TargetPlatformVersion
if (!targetPlatformVersion.empty()) {
e1.Element("WindowsTargetPlatformMinVersion", targetPlatformVersion);
@@ -4693,10 +4697,8 @@ void cmVisualStudio10TargetGenerator::GetCSharpSourceProperties(
void cmVisualStudio10TargetGenerator::WriteCSharpSourceProperties(
Elem& e2, const std::map<std::string, std::string>& tags)
{
- if (!tags.empty()) {
- for (const auto& i : tags) {
- e2.Element(i.first.c_str(), i.second);
- }
+ for (const auto& i : tags) {
+ e2.Element(i.first.c_str(), i.second);
}
}
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 68db332e1..860b8093e 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -72,10 +72,14 @@ private:
void WriteExcludeFromBuild(Elem& e2,
std::vector<size_t> const& exclude_configs);
void WriteAllSources(Elem& e0);
+ void WritePackageReferences(Elem& e0);
+ void WritePackageReference(Elem& e1, std::string const& ref,
+ std::string const& version);
void WriteDotNetReferences(Elem& e0);
void WriteDotNetReference(Elem& e1, std::string const& ref,
std::string const& hint,
std::string const& config);
+ void WriteImports(Elem& e0);
void WriteDotNetReferenceCustomTags(Elem& e2, std::string const& ref);
void WriteEmbeddedResourceGroup(Elem& e0);
void WriteWinRTReferences(Elem& e0);
@@ -166,7 +170,7 @@ private:
void WriteGroupSources(Elem& e0, std::string const& name,
ToolSources const& sources,
std::vector<cmSourceGroup>&);
- void AddMissingSourceGroups(std::set<cmSourceGroup*>& groupsUsed,
+ void AddMissingSourceGroups(std::set<cmSourceGroup const*>& groupsUsed,
const std::vector<cmSourceGroup>& allGroups);
bool IsResxHeader(const std::string& headerFile);
bool IsXamlHeader(const std::string& headerFile);
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
index 5c3e533b8..e1b0c70b6 100644
--- a/Source/cmVisualStudioGeneratorOptions.cxx
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -374,19 +374,19 @@ void cmVisualStudioGeneratorOptions::StoreUnknownFlag(std::string const& flag)
{
// Look for Intel Fortran flags that do not map well in the flag table.
if (this->CurrentTool == FortranCompiler) {
- if (flag == "/dbglibs") {
+ if (flag == "/dbglibs" || flag == "-dbglibs") {
this->FortranRuntimeDebug = true;
return;
}
- if (flag == "/threads") {
+ if (flag == "/threads" || flag == "-threads") {
this->FortranRuntimeMT = true;
return;
}
- if (flag == "/libs:dll") {
+ if (flag == "/libs:dll" || flag == "-libs:dll") {
this->FortranRuntimeDLL = true;
return;
}
- if (flag == "/libs:static") {
+ if (flag == "/libs:static" || flag == "-libs:static") {
this->FortranRuntimeDLL = false;
return;
}
@@ -438,14 +438,13 @@ void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions(
const char* sep = "";
std::vector<std::string>::const_iterator de =
cmRemoveDuplicates(this->Defines);
- for (std::vector<std::string>::const_iterator di = this->Defines.begin();
- di != de; ++di) {
+ for (std::string const& di : cmMakeRange(this->Defines.cbegin(), de)) {
// Escape the definition for the compiler.
std::string define;
if (this->Version < cmGlobalVisualStudioGenerator::VS10) {
- define = this->LocalGenerator->EscapeForShell(*di, true);
+ define = this->LocalGenerator->EscapeForShell(di, true);
} else {
- define = *di;
+ define = di;
}
// Escape this flag for the MSBuild.
if (this->Version >= cmGlobalVisualStudioGenerator::VS10) {
diff --git a/Source/cmWorkerPool.cxx b/Source/cmWorkerPool.cxx
new file mode 100644
index 000000000..cbf070e91
--- /dev/null
+++ b/Source/cmWorkerPool.cxx
@@ -0,0 +1,763 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmWorkerPool.h"
+
+#include "cmRange.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVSignalHackRAII.h" // IWYU pragma: keep
+#include "cm_uv.h"
+
+#include <algorithm>
+#include <array>
+#include <condition_variable>
+#include <deque>
+#include <functional>
+#include <mutex>
+#include <stddef.h>
+#include <thread>
+
+/**
+ * @brief libuv pipe buffer class
+ */
+class cmUVPipeBuffer
+{
+public:
+ typedef cmRange<char const*> DataRange;
+ typedef std::function<void(DataRange)> DataFunction;
+ /// On error the ssize_t argument is a non zero libuv error code
+ typedef std::function<void(ssize_t)> EndFunction;
+
+public:
+ /**
+ * Reset to construction state
+ */
+ void reset();
+
+ /**
+ * Initializes uv_pipe(), uv_stream() and uv_handle()
+ * @return true on success
+ */
+ bool init(uv_loop_t* uv_loop);
+
+ /**
+ * Start reading
+ * @return true on success
+ */
+ bool startRead(DataFunction dataFunction, EndFunction endFunction);
+
+ //! libuv pipe
+ uv_pipe_t* uv_pipe() const { return UVPipe_.get(); }
+ //! uv_pipe() casted to libuv stream
+ uv_stream_t* uv_stream() const { return static_cast<uv_stream_t*>(UVPipe_); }
+ //! uv_pipe() casted to libuv handle
+ uv_handle_t* uv_handle() { return static_cast<uv_handle_t*>(UVPipe_); }
+
+private:
+ // -- Libuv callbacks
+ static void UVAlloc(uv_handle_t* handle, size_t suggestedSize,
+ uv_buf_t* buf);
+ static void UVData(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
+
+private:
+ cm::uv_pipe_ptr UVPipe_;
+ std::vector<char> Buffer_;
+ DataFunction DataFunction_;
+ EndFunction EndFunction_;
+};
+
+void cmUVPipeBuffer::reset()
+{
+ if (UVPipe_.get() != nullptr) {
+ EndFunction_ = nullptr;
+ DataFunction_ = nullptr;
+ Buffer_.clear();
+ Buffer_.shrink_to_fit();
+ UVPipe_.reset();
+ }
+}
+
+bool cmUVPipeBuffer::init(uv_loop_t* uv_loop)
+{
+ reset();
+ if (uv_loop == nullptr) {
+ return false;
+ }
+ int ret = UVPipe_.init(*uv_loop, 0, this);
+ return (ret == 0);
+}
+
+bool cmUVPipeBuffer::startRead(DataFunction dataFunction,
+ EndFunction endFunction)
+{
+ if (UVPipe_.get() == nullptr) {
+ return false;
+ }
+ if (!dataFunction || !endFunction) {
+ return false;
+ }
+ DataFunction_ = std::move(dataFunction);
+ EndFunction_ = std::move(endFunction);
+ int ret = uv_read_start(uv_stream(), &cmUVPipeBuffer::UVAlloc,
+ &cmUVPipeBuffer::UVData);
+ return (ret == 0);
+}
+
+void cmUVPipeBuffer::UVAlloc(uv_handle_t* handle, size_t suggestedSize,
+ uv_buf_t* buf)
+{
+ auto& pipe = *reinterpret_cast<cmUVPipeBuffer*>(handle->data);
+ pipe.Buffer_.resize(suggestedSize);
+ buf->base = pipe.Buffer_.data();
+ buf->len = static_cast<unsigned long>(pipe.Buffer_.size());
+}
+
+void cmUVPipeBuffer::UVData(uv_stream_t* stream, ssize_t nread,
+ const uv_buf_t* buf)
+{
+ auto& pipe = *reinterpret_cast<cmUVPipeBuffer*>(stream->data);
+ if (nread > 0) {
+ if (buf->base != nullptr) {
+ // Call data function
+ pipe.DataFunction_(DataRange(buf->base, buf->base + nread));
+ }
+ } else if (nread < 0) {
+ // Save the end function on the stack before resetting the pipe
+ EndFunction efunc;
+ efunc.swap(pipe.EndFunction_);
+ // Reset pipe before calling the end function
+ pipe.reset();
+ // Call end function
+ efunc((nread == UV_EOF) ? 0 : nread);
+ }
+}
+
+/**
+ * @brief External process management class
+ */
+class cmUVReadOnlyProcess
+{
+public:
+ // -- Types
+ //! @brief Process settings
+ struct SetupT
+ {
+ std::string WorkingDirectory;
+ std::vector<std::string> Command;
+ cmWorkerPool::ProcessResultT* Result = nullptr;
+ bool MergedOutput = false;
+ };
+
+public:
+ // -- Const accessors
+ SetupT const& Setup() const { return Setup_; }
+ cmWorkerPool::ProcessResultT* Result() const { return Setup_.Result; }
+ bool IsStarted() const { return IsStarted_; }
+ bool IsFinished() const { return IsFinished_; }
+
+ // -- Runtime
+ void setup(cmWorkerPool::ProcessResultT* result, bool mergedOutput,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory = std::string());
+ bool start(uv_loop_t* uv_loop, std::function<void()> finishedCallback);
+
+private:
+ // -- Libuv callbacks
+ static void UVExit(uv_process_t* handle, int64_t exitStatus, int termSignal);
+ void UVPipeOutData(cmUVPipeBuffer::DataRange data);
+ void UVPipeOutEnd(ssize_t error);
+ void UVPipeErrData(cmUVPipeBuffer::DataRange data);
+ void UVPipeErrEnd(ssize_t error);
+ void UVTryFinish();
+
+private:
+ // -- Setup
+ SetupT Setup_;
+ // -- Runtime
+ bool IsStarted_ = false;
+ bool IsFinished_ = false;
+ std::function<void()> FinishedCallback_;
+ std::vector<const char*> CommandPtr_;
+ std::array<uv_stdio_container_t, 3> UVOptionsStdIO_;
+ uv_process_options_t UVOptions_;
+ cm::uv_process_ptr UVProcess_;
+ cmUVPipeBuffer UVPipeOut_;
+ cmUVPipeBuffer UVPipeErr_;
+};
+
+void cmUVReadOnlyProcess::setup(cmWorkerPool::ProcessResultT* result,
+ bool mergedOutput,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory)
+{
+ Setup_.WorkingDirectory = workingDirectory;
+ Setup_.Command = command;
+ Setup_.Result = result;
+ Setup_.MergedOutput = mergedOutput;
+}
+
+bool cmUVReadOnlyProcess::start(uv_loop_t* uv_loop,
+ std::function<void()> finishedCallback)
+{
+ if (IsStarted() || (Result() == nullptr)) {
+ return false;
+ }
+
+ // Reset result before the start
+ Result()->reset();
+
+ // Fill command string pointers
+ if (!Setup().Command.empty()) {
+ CommandPtr_.reserve(Setup().Command.size() + 1);
+ for (std::string const& arg : Setup().Command) {
+ CommandPtr_.push_back(arg.c_str());
+ }
+ CommandPtr_.push_back(nullptr);
+ } else {
+ Result()->ErrorMessage = "Empty command";
+ }
+
+ if (!Result()->error()) {
+ if (!UVPipeOut_.init(uv_loop)) {
+ Result()->ErrorMessage = "libuv stdout pipe initialization failed";
+ }
+ }
+ if (!Result()->error()) {
+ if (!UVPipeErr_.init(uv_loop)) {
+ Result()->ErrorMessage = "libuv stderr pipe initialization failed";
+ }
+ }
+ if (!Result()->error()) {
+ // -- Setup process stdio options
+ // stdin
+ UVOptionsStdIO_[0].flags = UV_IGNORE;
+ UVOptionsStdIO_[0].data.stream = nullptr;
+ // stdout
+ UVOptionsStdIO_[1].flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ UVOptionsStdIO_[1].data.stream = UVPipeOut_.uv_stream();
+ // stderr
+ UVOptionsStdIO_[2].flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ UVOptionsStdIO_[2].data.stream = UVPipeErr_.uv_stream();
+
+ // -- Setup process options
+ std::fill_n(reinterpret_cast<char*>(&UVOptions_), sizeof(UVOptions_), 0);
+ UVOptions_.exit_cb = &cmUVReadOnlyProcess::UVExit;
+ UVOptions_.file = CommandPtr_[0];
+ UVOptions_.args = const_cast<char**>(CommandPtr_.data());
+ UVOptions_.cwd = Setup_.WorkingDirectory.c_str();
+ UVOptions_.flags = UV_PROCESS_WINDOWS_HIDE;
+ UVOptions_.stdio_count = static_cast<int>(UVOptionsStdIO_.size());
+ UVOptions_.stdio = UVOptionsStdIO_.data();
+
+ // -- Spawn process
+ int uvErrorCode = UVProcess_.spawn(*uv_loop, UVOptions_, this);
+ if (uvErrorCode != 0) {
+ Result()->ErrorMessage = "libuv process spawn failed";
+ if (const char* uvErr = uv_strerror(uvErrorCode)) {
+ Result()->ErrorMessage += ": ";
+ Result()->ErrorMessage += uvErr;
+ }
+ }
+ }
+ // -- Start reading from stdio streams
+ if (!Result()->error()) {
+ if (!UVPipeOut_.startRead(
+ [this](cmUVPipeBuffer::DataRange range) {
+ this->UVPipeOutData(range);
+ },
+ [this](ssize_t error) { this->UVPipeOutEnd(error); })) {
+ Result()->ErrorMessage = "libuv start reading from stdout pipe failed";
+ }
+ }
+ if (!Result()->error()) {
+ if (!UVPipeErr_.startRead(
+ [this](cmUVPipeBuffer::DataRange range) {
+ this->UVPipeErrData(range);
+ },
+ [this](ssize_t error) { this->UVPipeErrEnd(error); })) {
+ Result()->ErrorMessage = "libuv start reading from stderr pipe failed";
+ }
+ }
+
+ if (!Result()->error()) {
+ IsStarted_ = true;
+ FinishedCallback_ = std::move(finishedCallback);
+ } else {
+ // Clear libuv handles and finish
+ UVProcess_.reset();
+ UVPipeOut_.reset();
+ UVPipeErr_.reset();
+ CommandPtr_.clear();
+ }
+
+ return IsStarted();
+}
+
+void cmUVReadOnlyProcess::UVExit(uv_process_t* handle, int64_t exitStatus,
+ int termSignal)
+{
+ auto& proc = *reinterpret_cast<cmUVReadOnlyProcess*>(handle->data);
+ if (proc.IsStarted() && !proc.IsFinished()) {
+ // Set error message on demand
+ proc.Result()->ExitStatus = exitStatus;
+ proc.Result()->TermSignal = termSignal;
+ if (!proc.Result()->error()) {
+ if (termSignal != 0) {
+ proc.Result()->ErrorMessage = "Process was terminated by signal ";
+ proc.Result()->ErrorMessage +=
+ std::to_string(proc.Result()->TermSignal);
+ } else if (exitStatus != 0) {
+ proc.Result()->ErrorMessage = "Process failed with return value ";
+ proc.Result()->ErrorMessage +=
+ std::to_string(proc.Result()->ExitStatus);
+ }
+ }
+
+ // Reset process handle
+ proc.UVProcess_.reset();
+ // Try finish
+ proc.UVTryFinish();
+ }
+}
+
+void cmUVReadOnlyProcess::UVPipeOutData(cmUVPipeBuffer::DataRange data)
+{
+ Result()->StdOut.append(data.begin(), data.end());
+}
+
+void cmUVReadOnlyProcess::UVPipeOutEnd(ssize_t error)
+{
+ // Process pipe error
+ if ((error != 0) && !Result()->error()) {
+ Result()->ErrorMessage =
+ "Reading from stdout pipe failed with libuv error code ";
+ Result()->ErrorMessage += std::to_string(error);
+ }
+ // Try finish
+ UVTryFinish();
+}
+
+void cmUVReadOnlyProcess::UVPipeErrData(cmUVPipeBuffer::DataRange data)
+{
+ std::string* str =
+ Setup_.MergedOutput ? &Result()->StdOut : &Result()->StdErr;
+ str->append(data.begin(), data.end());
+}
+
+void cmUVReadOnlyProcess::UVPipeErrEnd(ssize_t error)
+{
+ // Process pipe error
+ if ((error != 0) && !Result()->error()) {
+ Result()->ErrorMessage =
+ "Reading from stderr pipe failed with libuv error code ";
+ Result()->ErrorMessage += std::to_string(error);
+ }
+ // Try finish
+ UVTryFinish();
+}
+
+void cmUVReadOnlyProcess::UVTryFinish()
+{
+ // There still might be data in the pipes after the process has finished.
+ // Therefore check if the process is finished AND all pipes are closed
+ // before signaling the worker thread to continue.
+ if ((UVProcess_.get() != nullptr) || (UVPipeOut_.uv_pipe() != nullptr) ||
+ (UVPipeErr_.uv_pipe() != nullptr)) {
+ return;
+ }
+ IsFinished_ = true;
+ FinishedCallback_();
+}
+
+/**
+ * @brief Worker pool worker thread
+ */
+class cmWorkerPoolWorker
+{
+public:
+ cmWorkerPoolWorker(uv_loop_t& uvLoop);
+ ~cmWorkerPoolWorker();
+
+ cmWorkerPoolWorker(cmWorkerPoolWorker const&) = delete;
+ cmWorkerPoolWorker& operator=(cmWorkerPoolWorker const&) = delete;
+
+ /**
+ * Set the internal thread
+ */
+ void SetThread(std::thread&& aThread) { Thread_ = std::move(aThread); }
+
+ /**
+ * Run an external process
+ */
+ bool RunProcess(cmWorkerPool::ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory);
+
+private:
+ // -- Libuv callbacks
+ static void UVProcessStart(uv_async_t* handle);
+ void UVProcessFinished();
+
+private:
+ // -- Process management
+ struct
+ {
+ std::mutex Mutex;
+ cm::uv_async_ptr Request;
+ std::condition_variable Condition;
+ std::unique_ptr<cmUVReadOnlyProcess> ROP;
+ } Proc_;
+ // -- System thread
+ std::thread Thread_;
+};
+
+cmWorkerPoolWorker::cmWorkerPoolWorker(uv_loop_t& uvLoop)
+{
+ Proc_.Request.init(uvLoop, &cmWorkerPoolWorker::UVProcessStart, this);
+}
+
+cmWorkerPoolWorker::~cmWorkerPoolWorker()
+{
+ if (Thread_.joinable()) {
+ Thread_.join();
+ }
+}
+
+bool cmWorkerPoolWorker::RunProcess(cmWorkerPool::ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory)
+{
+ if (command.empty()) {
+ return false;
+ }
+ // Create process instance
+ {
+ std::lock_guard<std::mutex> lock(Proc_.Mutex);
+ Proc_.ROP = cm::make_unique<cmUVReadOnlyProcess>();
+ Proc_.ROP->setup(&result, true, command, workingDirectory);
+ }
+ // Send asynchronous process start request to libuv loop
+ Proc_.Request.send();
+ // Wait until the process has been finished and destroyed
+ {
+ std::unique_lock<std::mutex> ulock(Proc_.Mutex);
+ while (Proc_.ROP) {
+ Proc_.Condition.wait(ulock);
+ }
+ }
+ return !result.error();
+}
+
+void cmWorkerPoolWorker::UVProcessStart(uv_async_t* handle)
+{
+ auto* wrk = reinterpret_cast<cmWorkerPoolWorker*>(handle->data);
+ bool startFailed = false;
+ {
+ auto& Proc = wrk->Proc_;
+ std::lock_guard<std::mutex> lock(Proc.Mutex);
+ if (Proc.ROP && !Proc.ROP->IsStarted()) {
+ startFailed =
+ !Proc.ROP->start(handle->loop, [wrk] { wrk->UVProcessFinished(); });
+ }
+ }
+ // Clean up if starting of the process failed
+ if (startFailed) {
+ wrk->UVProcessFinished();
+ }
+}
+
+void cmWorkerPoolWorker::UVProcessFinished()
+{
+ {
+ std::lock_guard<std::mutex> lock(Proc_.Mutex);
+ if (Proc_.ROP && (Proc_.ROP->IsFinished() || !Proc_.ROP->IsStarted())) {
+ Proc_.ROP.reset();
+ }
+ }
+ // Notify idling thread
+ Proc_.Condition.notify_one();
+}
+
+/**
+ * @brief Private worker pool internals
+ */
+class cmWorkerPoolInternal
+{
+public:
+ // -- Constructors
+ cmWorkerPoolInternal(cmWorkerPool* pool);
+ ~cmWorkerPoolInternal();
+
+ /**
+ * Runs the libuv loop.
+ */
+ bool Process();
+
+ /**
+ * Clear queue and abort threads.
+ */
+ void Abort();
+
+ /**
+ * Push a job to the queue and notify a worker.
+ */
+ bool PushJob(cmWorkerPool::JobHandleT&& jobHandle);
+
+ /**
+ * Worker thread main loop method.
+ */
+ void Work(unsigned int workerIndex);
+
+ // -- Request slots
+ static void UVSlotBegin(uv_async_t* handle);
+ static void UVSlotEnd(uv_async_t* handle);
+
+public:
+ // -- UV loop
+#ifdef CMAKE_UV_SIGNAL_HACK
+ std::unique_ptr<cmUVSignalHackRAII> UVHackRAII;
+#endif
+ std::unique_ptr<uv_loop_t> UVLoop;
+ cm::uv_async_ptr UVRequestBegin;
+ cm::uv_async_ptr UVRequestEnd;
+
+ // -- Thread pool and job queue
+ std::mutex Mutex;
+ bool Processing = false;
+ bool Aborting = false;
+ bool FenceProcessing = false;
+ unsigned int WorkersRunning = 0;
+ unsigned int WorkersIdle = 0;
+ unsigned int JobsProcessing = 0;
+ std::deque<cmWorkerPool::JobHandleT> Queue;
+ std::condition_variable Condition;
+ std::vector<std::unique_ptr<cmWorkerPoolWorker>> Workers;
+
+ // -- References
+ cmWorkerPool* Pool = nullptr;
+};
+
+void cmWorkerPool::ProcessResultT::reset()
+{
+ ExitStatus = 0;
+ TermSignal = 0;
+ if (!StdOut.empty()) {
+ StdOut.clear();
+ StdOut.shrink_to_fit();
+ }
+ if (!StdErr.empty()) {
+ StdErr.clear();
+ StdErr.shrink_to_fit();
+ }
+ if (!ErrorMessage.empty()) {
+ ErrorMessage.clear();
+ ErrorMessage.shrink_to_fit();
+ }
+}
+
+cmWorkerPoolInternal::cmWorkerPoolInternal(cmWorkerPool* pool)
+ : Pool(pool)
+{
+ // Initialize libuv loop
+ uv_disable_stdio_inheritance();
+#ifdef CMAKE_UV_SIGNAL_HACK
+ UVHackRAII = cm::make_unique<cmUVSignalHackRAII>();
+#endif
+ UVLoop = cm::make_unique<uv_loop_t>();
+ uv_loop_init(UVLoop.get());
+}
+
+cmWorkerPoolInternal::~cmWorkerPoolInternal()
+{
+ uv_loop_close(UVLoop.get());
+}
+
+bool cmWorkerPoolInternal::Process()
+{
+ // Reset state flags
+ Processing = true;
+ Aborting = false;
+ // Initialize libuv asynchronous request
+ UVRequestBegin.init(*UVLoop, &cmWorkerPoolInternal::UVSlotBegin, this);
+ UVRequestEnd.init(*UVLoop, &cmWorkerPoolInternal::UVSlotEnd, this);
+ // Send begin request
+ UVRequestBegin.send();
+ // Run libuv loop
+ bool success = (uv_run(UVLoop.get(), UV_RUN_DEFAULT) == 0);
+ // Update state flags
+ Processing = false;
+ Aborting = false;
+ return success;
+}
+
+void cmWorkerPoolInternal::Abort()
+{
+ bool notifyThreads = false;
+ // Clear all jobs and set abort flag
+ {
+ std::lock_guard<std::mutex> guard(Mutex);
+ if (Processing && !Aborting) {
+ // Register abort and clear queue
+ Aborting = true;
+ Queue.clear();
+ notifyThreads = true;
+ }
+ }
+ if (notifyThreads) {
+ // Wake threads
+ Condition.notify_all();
+ }
+}
+
+inline bool cmWorkerPoolInternal::PushJob(cmWorkerPool::JobHandleT&& jobHandle)
+{
+ std::lock_guard<std::mutex> guard(Mutex);
+ if (Aborting) {
+ return false;
+ }
+ // Append the job to the queue
+ Queue.emplace_back(std::move(jobHandle));
+ // Notify an idle worker if there's one
+ if (WorkersIdle != 0) {
+ Condition.notify_one();
+ }
+ // Return success
+ return true;
+}
+
+void cmWorkerPoolInternal::UVSlotBegin(uv_async_t* handle)
+{
+ auto& gint = *reinterpret_cast<cmWorkerPoolInternal*>(handle->data);
+ // Create worker threads
+ {
+ unsigned int const num = gint.Pool->ThreadCount();
+ // Create workers
+ gint.Workers.reserve(num);
+ for (unsigned int ii = 0; ii != num; ++ii) {
+ gint.Workers.emplace_back(
+ cm::make_unique<cmWorkerPoolWorker>(*gint.UVLoop));
+ }
+ // Start worker threads
+ for (unsigned int ii = 0; ii != num; ++ii) {
+ gint.Workers[ii]->SetThread(
+ std::thread(&cmWorkerPoolInternal::Work, &gint, ii));
+ }
+ }
+ // Destroy begin request
+ gint.UVRequestBegin.reset();
+}
+
+void cmWorkerPoolInternal::UVSlotEnd(uv_async_t* handle)
+{
+ auto& gint = *reinterpret_cast<cmWorkerPoolInternal*>(handle->data);
+ // Join and destroy worker threads
+ gint.Workers.clear();
+ // Destroy end request
+ gint.UVRequestEnd.reset();
+}
+
+void cmWorkerPoolInternal::Work(unsigned int workerIndex)
+{
+ cmWorkerPool::JobHandleT jobHandle;
+ std::unique_lock<std::mutex> uLock(Mutex);
+ // Increment running workers count
+ ++WorkersRunning;
+ // Enter worker main loop
+ while (true) {
+ // Abort on request
+ if (Aborting) {
+ break;
+ }
+ // Wait for new jobs
+ if (Queue.empty()) {
+ ++WorkersIdle;
+ Condition.wait(uLock);
+ --WorkersIdle;
+ continue;
+ }
+
+ // Check for fence jobs
+ if (FenceProcessing || Queue.front()->IsFence()) {
+ if (JobsProcessing != 0) {
+ Condition.wait(uLock);
+ continue;
+ }
+ // No jobs get processed. Set the fence job processing flag.
+ FenceProcessing = true;
+ }
+
+ // Pop next job from queue
+ jobHandle = std::move(Queue.front());
+ Queue.pop_front();
+
+ // Unlocked scope for job processing
+ ++JobsProcessing;
+ {
+ uLock.unlock();
+ jobHandle->Work(Pool, workerIndex); // Process job
+ jobHandle.reset(); // Destroy job
+ uLock.lock();
+ }
+ --JobsProcessing;
+
+ // Was this a fence job?
+ if (FenceProcessing) {
+ FenceProcessing = false;
+ Condition.notify_all();
+ }
+ }
+
+ // Decrement running workers count
+ if (--WorkersRunning == 0) {
+ // Last worker thread about to finish. Send libuv event.
+ UVRequestEnd.send();
+ }
+}
+
+cmWorkerPool::JobT::~JobT() = default;
+
+bool cmWorkerPool::JobT::RunProcess(ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory)
+{
+ // Get worker by index
+ auto* wrk = Pool_->Int_->Workers.at(WorkerIndex_).get();
+ return wrk->RunProcess(result, command, workingDirectory);
+}
+
+cmWorkerPool::cmWorkerPool()
+ : Int_(cm::make_unique<cmWorkerPoolInternal>(this))
+{
+}
+
+cmWorkerPool::~cmWorkerPool() = default;
+
+void cmWorkerPool::SetThreadCount(unsigned int threadCount)
+{
+ if (!Int_->Processing) {
+ ThreadCount_ = (threadCount > 0) ? threadCount : 1u;
+ }
+}
+
+bool cmWorkerPool::Process(void* userData)
+{
+ // Setup user data
+ UserData_ = userData;
+ // Run libuv loop
+ bool success = Int_->Process();
+ // Clear user data
+ UserData_ = nullptr;
+ // Return
+ return success;
+}
+
+bool cmWorkerPool::PushJob(JobHandleT&& jobHandle)
+{
+ return Int_->PushJob(std::move(jobHandle));
+}
+
+void cmWorkerPool::Abort()
+{
+ Int_->Abort();
+}
diff --git a/Source/cmWorkerPool.h b/Source/cmWorkerPool.h
new file mode 100644
index 000000000..f08bb4f8d
--- /dev/null
+++ b/Source/cmWorkerPool.h
@@ -0,0 +1,226 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmWorkerPool_h
+#define cmWorkerPool_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmAlgorithms.h" // IWYU pragma: keep
+
+#include <memory> // IWYU pragma: keep
+#include <stdint.h>
+#include <string>
+#include <utility>
+#include <vector>
+
+// -- Types
+class cmWorkerPoolInternal;
+
+/** @class cmWorkerPool
+ * @brief Thread pool with job queue
+ */
+class cmWorkerPool
+{
+public:
+ /**
+ * Return value and output of an external process.
+ */
+ struct ProcessResultT
+ {
+ void reset();
+ bool error() const
+ {
+ return (ExitStatus != 0) || (TermSignal != 0) || !ErrorMessage.empty();
+ }
+
+ std::int64_t ExitStatus = 0;
+ int TermSignal = 0;
+ std::string StdOut;
+ std::string StdErr;
+ std::string ErrorMessage;
+ };
+
+ /**
+ * Abstract job class for concurrent job processing.
+ */
+ class JobT
+ {
+ public:
+ JobT(JobT const&) = delete;
+ JobT& operator=(JobT const&) = delete;
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~JobT();
+
+ /**
+ * Fence job flag
+ *
+ * Fence jobs require that:
+ * - all jobs before in the queue have been processed
+ * - no jobs later in the queue will be processed before this job was
+ * processed
+ */
+ bool IsFence() const { return Fence_; }
+
+ protected:
+ /**
+ * Protected default constructor
+ */
+ JobT(bool fence = false)
+ : Fence_(fence)
+ {
+ }
+
+ /**
+ * Abstract processing interface that must be implement in derived classes.
+ */
+ virtual void Process() = 0;
+
+ /**
+ * Get the worker pool.
+ * Only valid during the JobT::Process() call!
+ */
+ cmWorkerPool* Pool() const { return Pool_; }
+
+ /**
+ * Get the user data.
+ * Only valid during the JobT::Process() call!
+ */
+ void* UserData() const { return Pool_->UserData(); };
+
+ /**
+ * Get the worker index.
+ * This is the index of the thread processing this job and is in the range
+ * [0..ThreadCount).
+ * Concurrently processing jobs will never have the same WorkerIndex().
+ * Only valid during the JobT::Process() call!
+ */
+ unsigned int WorkerIndex() const { return WorkerIndex_; }
+
+ /**
+ * Run an external read only process.
+ * Use only during JobT::Process() call!
+ */
+ bool RunProcess(ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory);
+
+ private:
+ //! Needs access to Work()
+ friend class cmWorkerPoolInternal;
+ //! Worker thread entry method.
+ void Work(cmWorkerPool* pool, unsigned int workerIndex)
+ {
+ Pool_ = pool;
+ WorkerIndex_ = workerIndex;
+ this->Process();
+ }
+
+ private:
+ cmWorkerPool* Pool_ = nullptr;
+ unsigned int WorkerIndex_ = 0;
+ bool Fence_ = false;
+ };
+
+ /**
+ * Job handle type
+ */
+ typedef std::unique_ptr<JobT> JobHandleT;
+
+ /**
+ * Fence job base class
+ */
+ class JobFenceT : public JobT
+ {
+ public:
+ JobFenceT()
+ : JobT(true)
+ {
+ }
+ //! Does nothing
+ void Process() override{};
+ };
+
+ /**
+ * Fence job that aborts the worker pool.
+ *
+ * Useful as the last job in the job queue.
+ */
+ class JobEndT : JobFenceT
+ {
+ public:
+ //! Does nothing
+ void Process() override { Pool()->Abort(); }
+ };
+
+public:
+ // -- Methods
+ cmWorkerPool();
+ ~cmWorkerPool();
+
+ /**
+ * Number of worker threads.
+ */
+ unsigned int ThreadCount() const { return ThreadCount_; }
+
+ /**
+ * Set the number of worker threads.
+ *
+ * Calling this method during Process() has no effect.
+ */
+ void SetThreadCount(unsigned int threadCount);
+
+ /**
+ * Blocking function that starts threads to process all Jobs in the queue.
+ *
+ * This method blocks until a job calls the Abort() method.
+ * @arg threadCount Number of threads to process jobs.
+ * @arg userData Common user data pointer available in all Jobs.
+ */
+ bool Process(void* userData = nullptr);
+
+ /**
+ * User data reference passed to Process().
+ *
+ * Only valid during Process().
+ */
+ void* UserData() const { return UserData_; }
+
+ // -- Job processing interface
+
+ /**
+ * Clears the job queue and aborts all worker threads.
+ *
+ * This method is thread safe and can be called from inside a job.
+ */
+ void Abort();
+
+ /**
+ * Push job to the queue.
+ *
+ * This method is thread safe and can be called from inside a job or before
+ * Process().
+ */
+ bool PushJob(JobHandleT&& jobHandle);
+
+ /**
+ * Push job to the queue
+ *
+ * This method is thread safe and can be called from inside a job or before
+ * Process().
+ */
+ template <class T, typename... Args>
+ bool EmplaceJob(Args&&... args)
+ {
+ return PushJob(cm::make_unique<T>(std::forward<Args>(args)...));
+ }
+
+private:
+ void* UserData_ = nullptr;
+ unsigned int ThreadCount_ = 1;
+ std::unique_ptr<cmWorkerPoolInternal> Int_;
+};
+
+#endif
diff --git a/Source/cmWorkingDirectory.h b/Source/cmWorkingDirectory.h
index 1f18ce7a3..d4a164de6 100644
--- a/Source/cmWorkingDirectory.h
+++ b/Source/cmWorkingDirectory.h
@@ -22,6 +22,9 @@ public:
cmWorkingDirectory(std::string const& newdir);
~cmWorkingDirectory();
+ cmWorkingDirectory(const cmWorkingDirectory&) = delete;
+ cmWorkingDirectory& operator=(const cmWorkingDirectory&) = delete;
+
bool SetDirectory(std::string const& newdir);
void Pop();
bool Failed() const { return ResultCode != 0; }
diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx
index 1b161987a..c33bb7e8f 100644
--- a/Source/cmXCodeScheme.cxx
+++ b/Source/cmXCodeScheme.cxx
@@ -177,6 +177,11 @@ void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout,
WriteLaunchActionAttribute(xout, "stopOnEveryMainThreadCheckerIssue",
"XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP");
+ if (this->Target->GetTarget()->GetPropertyAsBool(
+ "XCODE_SCHEME_DEBUG_AS_ROOT")) {
+ xout.Attribute("debugAsWhichUser", "root");
+ }
+
// Diagnostics tab end
if (IsExecutable(this->Target)) {
diff --git a/Source/cmXMLWriter.cxx b/Source/cmXMLWriter.cxx
index 9d2a3c454..f1ce60814 100644
--- a/Source/cmXMLWriter.cxx
+++ b/Source/cmXMLWriter.cxx
@@ -23,7 +23,7 @@ cmXMLWriter::~cmXMLWriter()
void cmXMLWriter::StartDocument(const char* encoding)
{
- this->Output << "<?xml version=\"1.0\" encoding=\"" << encoding << "\"?>";
+ this->Output << R"(<?xml version="1.0" encoding=")" << encoding << "\"?>";
}
void cmXMLWriter::EndDocument()
diff --git a/Source/cmXMLWriter.h b/Source/cmXMLWriter.h
index 1df8a09d7..512e1031d 100644
--- a/Source/cmXMLWriter.h
+++ b/Source/cmXMLWriter.h
@@ -146,6 +146,8 @@ public:
xmlwr.StartDocument();
}
~cmXMLDocument() { xmlwr.EndDocument(); }
+ cmXMLDocument(const cmXMLDocument&) = delete;
+ cmXMLDocument& operator=(const cmXMLDocument&) = delete;
private:
friend class cmXMLElement;
@@ -172,6 +174,9 @@ public:
}
~cmXMLElement() { xmlwr.EndElement(); }
+ cmXMLElement(const cmXMLElement&) = delete;
+ cmXMLElement& operator=(const cmXMLElement&) = delete;
+
template <typename T>
cmXMLElement& Attribute(const char* name, T const& value)
{
diff --git a/Source/cm_utf8.c b/Source/cm_utf8.c
index 52af4a6f4..62e7e8c8c 100644
--- a/Source/cm_utf8.c
+++ b/Source/cm_utf8.c
@@ -2,6 +2,8 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cm_utf8.h"
+#include <string.h>
+
/*
RFC 3629
07-bit: 0xxxxxxx
@@ -71,7 +73,34 @@ const char* cm_utf8_decode_character(const char* first, const char* last,
return 0;
}
+ /* UTF-16 surrogate halves. */
+ if (0xD800 <= uc && uc <= 0xDFFF) {
+ return 0;
+ }
+
+ /* Invalid codepoints. */
+ if (0x10FFFF < uc) {
+ return 0;
+ }
+
*pc = uc;
return first;
}
}
+
+int cm_utf8_is_valid(const char* s)
+{
+ if (!s) {
+ return 0;
+ }
+
+ const char* last = s + strlen(s);
+ const char* pos = s;
+ unsigned int pc;
+
+ while (pos != last && (pos = cm_utf8_decode_character(pos, last, &pc))) {
+ /* Nothing to do. */
+ }
+
+ return pos == last;
+}
diff --git a/Source/cm_utf8.h b/Source/cm_utf8.h
index fcb43e0e4..27dc5591f 100644
--- a/Source/cm_utf8.h
+++ b/Source/cm_utf8.h
@@ -13,6 +13,10 @@ extern "C" {
const char* cm_utf8_decode_character(const char* first, const char* last,
unsigned int* pc);
+/** Returns whether a C string is a sequence of valid UTF-8 encoded Unicode
+ codepoints. Returns non-zero on success. */
+int cm_utf8_is_valid(const char* s);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 8023298f9..3772f0998 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -9,7 +9,7 @@
#include "cmDocumentationFormatter.h"
#include "cmDuration.h"
#include "cmExternalMakefileProjectGenerator.h"
-#include "cmFileTimeComparison.h"
+#include "cmFileTimeCache.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalGeneratorFactory.h"
@@ -48,7 +48,6 @@
#if defined(_WIN32) && !defined(__CYGWIN__)
# if !defined(CMAKE_BOOT_MINGW)
# include "cmGlobalBorlandMakefileGenerator.h"
-# include "cmGlobalGhsMultiGenerator.h"
# include "cmGlobalJOMMakefileGenerator.h"
# include "cmGlobalNMakeMakefileGenerator.h"
# include "cmGlobalVisualStudio10Generator.h"
@@ -84,6 +83,10 @@
# include "cmExtraEclipseCDT4Generator.h"
#endif
+#if defined(__linux__) || defined(_WIN32)
+# include "cmGlobalGhsMultiGenerator.h"
+#endif
+
#if defined(__APPLE__)
# if defined(CMAKE_BUILD_WITH_CMAKE)
# include "cmGlobalXCodeGenerator.h"
@@ -99,6 +102,7 @@
#include "cmsys/RegularExpression.hxx"
#include <algorithm>
#include <cstring>
+#include <initializer_list>
#include <iostream>
#include <iterator>
#include <memory> // IWYU pragma: keep
@@ -115,10 +119,8 @@ typedef std::unordered_map<std::string, Json::Value> JsonValueMapType;
} // namespace
-static bool cmakeCheckStampFile(const std::string& stampName,
- bool verbose = true);
-static bool cmakeCheckStampList(const std::string& stampList,
- bool verbose = true);
+static bool cmakeCheckStampFile(const std::string& stampName);
+static bool cmakeCheckStampList(const std::string& stampList);
void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/,
void* ctx, const char* /*unused*/,
@@ -139,7 +141,7 @@ cmake::cmake(Role role, cmState::Mode mode)
this->DebugOutput = false;
this->DebugTryCompile = false;
this->ClearBuildSystem = false;
- this->FileComparison = new cmFileTimeComparison;
+ this->FileTimeCache = new cmFileTimeCache;
this->State = new cmState;
this->State->SetMode(mode);
@@ -157,6 +159,9 @@ cmake::cmake(Role role, cmState::Mode mode)
#endif
this->GlobalGenerator = nullptr;
+ this->GeneratorInstanceSet = false;
+ this->GeneratorPlatformSet = false;
+ this->GeneratorToolsetSet = false;
this->CurrentWorkingMode = NORMAL_MODE;
#ifdef CMAKE_BUILD_WITH_CMAKE
@@ -172,6 +177,10 @@ cmake::cmake(Role role, cmState::Mode mode)
this->AddProjectCommands();
}
+ if (mode == cmState::Project) {
+ this->LoadEnvironmentPresets();
+ }
+
// Make sure we can capture the build tool output.
cmSystemTools::EnableVSConsoleOutput();
@@ -223,7 +232,7 @@ cmake::~cmake()
#ifdef CMAKE_BUILD_WITH_CMAKE
delete this->VariableWatch;
#endif
- delete this->FileComparison;
+ delete this->FileTimeCache;
}
#if defined(CMAKE_BUILD_WITH_CMAKE)
@@ -239,7 +248,7 @@ Json::Value cmake::ReportVersionJson() const
return version;
}
-Json::Value cmake::ReportCapabilitiesJson(bool haveServerMode) const
+Json::Value cmake::ReportCapabilitiesJson() const
{
Json::Value obj = Json::objectValue;
@@ -275,18 +284,19 @@ Json::Value cmake::ReportCapabilitiesJson(bool haveServerMode) const
generators.append(i.second);
}
obj["generators"] = generators;
- obj["serverMode"] = haveServerMode;
+ obj["fileApi"] = cmFileAPI::ReportCapabilities();
+ obj["serverMode"] = true;
return obj;
}
#endif
-std::string cmake::ReportCapabilities(bool haveServerMode) const
+std::string cmake::ReportCapabilities() const
{
std::string result;
#if defined(CMAKE_BUILD_WITH_CMAKE)
Json::FastWriter writer;
- result = writer.write(this->ReportCapabilitiesJson(haveServerMode));
+ result = writer.write(this->ReportCapabilitiesJson());
#else
result = "Not supported";
#endif
@@ -610,6 +620,35 @@ bool cmake::FindPackage(const std::vector<std::string>& args)
return packageFound;
}
+void cmake::LoadEnvironmentPresets()
+{
+ std::string envGenVar;
+ bool hasEnvironmentGenerator = false;
+ if (cmSystemTools::GetEnv("CMAKE_GENERATOR", envGenVar)) {
+ hasEnvironmentGenerator = true;
+ this->EnvironmentGenerator = envGenVar;
+ }
+
+ auto readGeneratorVar = [&](std::string name, std::string& key) {
+ std::string varValue;
+ if (cmSystemTools::GetEnv(name, varValue)) {
+ if (hasEnvironmentGenerator) {
+ key = varValue;
+ } else if (!this->GetIsInTryCompile()) {
+ std::string message = "Warning: Environment variable ";
+ message += name;
+ message += " will be ignored, because CMAKE_GENERATOR ";
+ message += "is not set.";
+ cmSystemTools::Message(message, "Warning");
+ }
+ }
+ };
+
+ readGeneratorVar("CMAKE_GENERATOR_INSTANCE", this->GeneratorInstance);
+ readGeneratorVar("CMAKE_GENERATOR_PLATFORM", this->GeneratorPlatform);
+ readGeneratorVar("CMAKE_GENERATOR_TOOLSET", this->GeneratorToolset);
+}
+
// Parse the args
void cmake::SetArgs(const std::vector<std::string>& args)
{
@@ -708,6 +747,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
this->GraphVizFile = path;
if (this->GraphVizFile.empty()) {
cmSystemTools::Error("No file specified for --graphviz");
+ return;
}
} else if (arg.find("--debug-trycompile", 0) == 0) {
std::cout << "debug trycompile on\n";
@@ -715,6 +755,14 @@ void cmake::SetArgs(const std::vector<std::string>& args)
} else if (arg.find("--debug-output", 0) == 0) {
std::cout << "Running with debug output on.\n";
this->SetDebugOutputOn(true);
+ } else if (arg.find("--loglevel=", 0) == 0) {
+ const auto logLevel =
+ StringToLogLevel(arg.substr(sizeof("--loglevel=") - 1));
+ if (logLevel == LogLevel::LOG_UNDEFINED) {
+ cmSystemTools::Error("Invalid level specified for --loglevel");
+ return;
+ }
+ this->SetLogLevel(logLevel);
} else if (arg.find("--trace-expand", 0) == 0) {
std::cout << "Running with expanded trace output on.\n";
this->SetTrace(true);
@@ -756,7 +804,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
cmSystemTools::Error("Multiple -A options not allowed");
return;
}
- this->GeneratorPlatform = value;
+ this->SetGeneratorPlatform(value);
havePlatform = true;
} else if (arg.find("-T", 0) == 0) {
std::string value = arg.substr(2);
@@ -772,7 +820,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
cmSystemTools::Error("Multiple -T options not allowed");
return;
}
- this->GeneratorToolset = value;
+ this->SetGeneratorToolset(value);
haveToolset = true;
} else if (arg.find("-G", 0) == 0) {
std::string value = arg.substr(2);
@@ -787,21 +835,31 @@ void cmake::SetArgs(const std::vector<std::string>& args)
}
cmGlobalGenerator* gen = this->CreateGlobalGenerator(value);
if (!gen) {
- const char* kdevError = nullptr;
+ std::string kdevError;
if (value.find("KDevelop3", 0) != std::string::npos) {
kdevError = "\nThe KDevelop3 generator is not supported anymore.";
}
- cmSystemTools::Error("Could not create named generator ",
- value.c_str(), kdevError);
+ cmSystemTools::Error("Could not create named generator " + value +
+ kdevError);
this->PrintGeneratorList();
- } else {
- this->SetGlobalGenerator(gen);
+ return;
}
+ this->SetGlobalGenerator(gen);
}
// no option assume it is the path to the source or an existing build
else {
- this->SetDirectoriesFromFile(arg.c_str());
+ this->SetDirectoriesFromFile(arg);
+ }
+ // Empty instance, platform and toolset if only a generator is specified
+ if (this->GlobalGenerator) {
+ this->GeneratorInstance = "";
+ if (!this->GeneratorPlatformSet) {
+ this->GeneratorPlatform = "";
+ }
+ if (!this->GeneratorToolsetSet) {
+ this->GeneratorToolset = "";
+ }
}
}
@@ -825,7 +883,26 @@ void cmake::SetArgs(const std::vector<std::string>& args)
}
}
-void cmake::SetDirectoriesFromFile(const char* arg)
+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 }
+ };
+
+ const auto levelStrLowCase = cmSystemTools::LowerCase(levelStr);
+
+ 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;
+}
+
+void cmake::SetDirectoriesFromFile(const std::string& arg)
{
// Check if the argument refers to a CMakeCache.txt or
// CMakeLists.txt file.
@@ -937,8 +1014,8 @@ int cmake::AddCMakePaths()
cmSystemTools::Error(
"Could not find CMAKE_ROOT !!!\n"
"CMake has most likely not been installed correctly.\n"
- "Modules directory not found in\n",
- cmSystemTools::GetCMakeRoot().c_str());
+ "Modules directory not found in\n" +
+ cmSystemTools::GetCMakeRoot());
return 0;
}
this->AddCacheEntry("CMAKE_ROOT", cmSystemTools::GetCMakeRoot().c_str(),
@@ -969,10 +1046,7 @@ void cmake::GetRegisteredGenerators(std::vector<GeneratorInfo>& generators,
std::vector<std::string> names = gen->GetGeneratorNames();
if (includeNamesWithPlatform) {
- std::vector<std::string> namesWithPlatform =
- gen->GetGeneratorNamesWithPlatform();
- names.insert(names.end(), namesWithPlatform.begin(),
- namesWithPlatform.end());
+ cmAppend(names, gen->GetGeneratorNamesWithPlatform());
}
for (std::string const& name : names) {
@@ -1105,7 +1179,7 @@ std::string cmake::FindCacheFile(const std::string& binaryDir)
if (cmSystemTools::FileExists(cmakeFiles)) {
std::string cachePathFound =
cmSystemTools::FileExistsInParentDirectories("CMakeCache.txt",
- cachePath.c_str(), "/");
+ cachePath, "/");
if (!cachePathFound.empty()) {
cachePath = cmSystemTools::GetFilenamePath(cachePathFound);
}
@@ -1416,8 +1490,7 @@ int cmake::ActualConfigure()
if (const std::string* instance =
this->State->GetInitializedCacheValue("CMAKE_GENERATOR_INSTANCE")) {
- if (!this->GeneratorInstance.empty() &&
- this->GeneratorInstance != *instance) {
+ if (this->GeneratorInstanceSet && this->GeneratorInstance != *instance) {
std::string message = "Error: generator instance: ";
message += this->GeneratorInstance;
message += "\nDoes not match the instance used previously: ";
@@ -1435,7 +1508,7 @@ int cmake::ActualConfigure()
if (const std::string* platformName =
this->State->GetInitializedCacheValue("CMAKE_GENERATOR_PLATFORM")) {
- if (!this->GeneratorPlatform.empty() &&
+ if (this->GeneratorPlatformSet &&
this->GeneratorPlatform != *platformName) {
std::string message = "Error: generator platform: ";
message += this->GeneratorPlatform;
@@ -1454,7 +1527,7 @@ int cmake::ActualConfigure()
if (const std::string* tsName =
this->State->GetInitializedCacheValue("CMAKE_GENERATOR_TOOLSET")) {
- if (!this->GeneratorToolset.empty() && this->GeneratorToolset != *tsName) {
+ if (this->GeneratorToolsetSet && this->GeneratorToolset != *tsName) {
std::string message = "Error: generator toolset: ";
message += this->GeneratorToolset;
message += "\nDoes not match the toolset used previously: ";
@@ -1532,6 +1605,16 @@ int cmake::ActualConfigure()
std::unique_ptr<cmGlobalGenerator> cmake::EvaluateDefaultGlobalGenerator()
{
+ if (!this->EnvironmentGenerator.empty()) {
+ cmGlobalGenerator* gen =
+ this->CreateGlobalGenerator(this->EnvironmentGenerator);
+ if (!gen) {
+ cmSystemTools::Error("CMAKE_GENERATOR was set but the specified "
+ "generator doesn't exist. Using CMake default.");
+ } else {
+ return std::unique_ptr<cmGlobalGenerator>(gen);
+ }
+ }
#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
std::string found;
// Try to find the newest VS installed on the computer and
@@ -1703,9 +1786,14 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
return ret;
}
ret = this->Generate();
+ if (ret) {
+ cmSystemTools::Message("CMake Generate step failed. "
+ "Build files cannot be regenerated correctly.");
+ return ret;
+ }
std::string message = "Build files have been written to: ";
message += this->GetHomeOutputDirectory();
- this->UpdateProgress(message.c_str(), -1);
+ this->UpdateProgress(message, -1);
return ret;
}
@@ -1720,7 +1808,7 @@ int cmake::Generate()
this->GlobalGenerator->Generate();
if (!this->GraphVizFile.empty()) {
std::cout << "Generate graphviz: " << this->GraphVizFile << std::endl;
- this->GenerateGraphViz(this->GraphVizFile.c_str());
+ this->GenerateGraphViz(this->GraphVizFile);
}
if (this->WarnUnusedCli) {
this->RunCheckForUnusedVariables();
@@ -1834,13 +1922,15 @@ void cmake::AddDefaultGenerators()
this->Generators.push_back(cmGlobalBorlandMakefileGenerator::NewFactory());
this->Generators.push_back(cmGlobalNMakeMakefileGenerator::NewFactory());
this->Generators.push_back(cmGlobalJOMMakefileGenerator::NewFactory());
- this->Generators.push_back(cmGlobalGhsMultiGenerator::NewFactory());
# endif
this->Generators.push_back(cmGlobalMSYSMakefileGenerator::NewFactory());
this->Generators.push_back(cmGlobalMinGWMakefileGenerator::NewFactory());
#endif
this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory());
#if defined(CMAKE_BUILD_WITH_CMAKE)
+# if defined(__linux__) || defined(_WIN32)
+ this->Generators.push_back(cmGlobalGhsMultiGenerator::NewFactory());
+# endif
this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory());
#endif
#if defined(CMAKE_USE_WMAKE)
@@ -1892,11 +1982,10 @@ bool cmake::LoadCache(const std::string& path, bool internal,
std::set<std::string>& includes)
{
bool result = this->State->LoadCache(path, internal, excludes, includes);
- static const char* entries[] = { "CMAKE_CACHE_MAJOR_VERSION",
- "CMAKE_CACHE_MINOR_VERSION" };
- for (const char* const* nameIt = cm::cbegin(entries);
- nameIt != cm::cend(entries); ++nameIt) {
- this->UnwatchUnusedCli(*nameIt);
+ static const auto entries = { "CMAKE_CACHE_MAJOR_VERSION",
+ "CMAKE_CACHE_MINOR_VERSION" };
+ for (auto const& entry : entries) {
+ this->UnwatchUnusedCli(entry);
}
return result;
}
@@ -1904,13 +1993,12 @@ bool cmake::LoadCache(const std::string& path, bool internal,
bool cmake::SaveCache(const std::string& path)
{
bool result = this->State->SaveCache(path, this->GetMessenger());
- static const char* entries[] = { "CMAKE_CACHE_MAJOR_VERSION",
- "CMAKE_CACHE_MINOR_VERSION",
- "CMAKE_CACHE_PATCH_VERSION",
- "CMAKE_CACHEFILE_DIR" };
- for (const char* const* nameIt = cm::cbegin(entries);
- nameIt != cm::cend(entries); ++nameIt) {
- this->UnwatchUnusedCli(*nameIt);
+ static const auto entries = { "CMAKE_CACHE_MAJOR_VERSION",
+ "CMAKE_CACHE_MINOR_VERSION",
+ "CMAKE_CACHE_PATCH_VERSION",
+ "CMAKE_CACHEFILE_DIR" };
+ for (auto const& entry : entries) {
+ this->UnwatchUnusedCli(entry);
}
return result;
}
@@ -1925,7 +2013,7 @@ void cmake::SetProgressCallback(ProgressCallbackType f)
this->ProgressCallback = std::move(f);
}
-void cmake::UpdateProgress(const char* msg, float prog)
+void cmake::UpdateProgress(const std::string& msg, float prog)
{
if (this->ProgressCallback && !this->State->GetIsInTryCompile()) {
this->ProgressCallback(msg, prog);
@@ -2017,8 +2105,8 @@ void cmake::UpdateConversionPathTable()
if (tablepath) {
cmsys::ifstream table(tablepath->c_str());
if (!table) {
- cmSystemTools::Error("CMAKE_PATH_TRANSLATION_FILE set to ",
- tablepath->c_str(), ". CMake can not open file.");
+ cmSystemTools::Error("CMAKE_PATH_TRANSLATION_FILE set to " + *tablepath +
+ ". CMake can not open file.");
cmSystemTools::ReportLastSystemError("CMake can not open file.");
} else {
std::string a, b;
@@ -2142,7 +2230,7 @@ int cmake::CheckBuildSystem()
std::string dep_newest = *dep++;
for (; dep != depends.end(); ++dep) {
int result = 0;
- if (this->FileComparison->FileTimeCompare(dep_newest, *dep, &result)) {
+ if (this->FileTimeCache->Compare(dep_newest, *dep, &result)) {
if (result < 0) {
dep_newest = *dep;
}
@@ -2161,7 +2249,7 @@ int cmake::CheckBuildSystem()
std::string out_oldest = *out++;
for (; out != outputs.end(); ++out) {
int result = 0;
- if (this->FileComparison->FileTimeCompare(out_oldest, *out, &result)) {
+ if (this->FileTimeCache->Compare(out_oldest, *out, &result)) {
if (result > 0) {
out_oldest = *out;
}
@@ -2178,8 +2266,7 @@ int cmake::CheckBuildSystem()
// If any output is older than any dependency then rerun.
{
int result = 0;
- if (!this->FileComparison->FileTimeCompare(out_oldest, dep_newest,
- &result) ||
+ if (!this->FileTimeCache->Compare(out_oldest, dep_newest, &result) ||
result < 0) {
if (verbose) {
std::ostringstream msg;
@@ -2229,7 +2316,7 @@ void cmake::MarkCliAsUsed(const std::string& variable)
this->UsedCliVariables[variable] = true;
}
-void cmake::GenerateGraphViz(const char* fileName) const
+void cmake::GenerateGraphViz(const std::string& fileName) const
{
#ifdef CMAKE_BUILD_WITH_CMAKE
cmGraphVizWriter gvWriter(this->GetGlobalGenerator());
@@ -2239,8 +2326,7 @@ void cmake::GenerateGraphViz(const char* fileName) const
std::string fallbackSettingsFile = this->GetHomeDirectory();
fallbackSettingsFile += "/CMakeGraphVizOptions.cmake";
- gvWriter.ReadSettings(settingsFile.c_str(), fallbackSettingsFile.c_str());
-
+ gvWriter.ReadSettings(settingsFile, fallbackSettingsFile);
gvWriter.WritePerTargetFiles(fileName);
gvWriter.WriteTargetDependersFiles(fileName);
gvWriter.WriteGlobalFile(fileName);
@@ -2326,8 +2412,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args)
}
cmGlobalGenerator* gen = this->CreateGlobalGenerator(value);
if (!gen) {
- cmSystemTools::Error("Could not create named generator ",
- value.c_str());
+ cmSystemTools::Error("Could not create named generator " + value);
this->PrintGeneratorList();
} else {
this->SetGlobalGenerator(gen);
@@ -2354,7 +2439,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args)
outFile += "/CMakeLists.txt";
// Copy file
- if (!cmSystemTools::cmCopyFile(inFile, outFile)) {
+ if (!cmsys::SystemTools::CopyFileAlways(inFile, outFile)) {
std::cerr << "Error copying file \"" << inFile << "\" to \"" << outFile
<< "\".\n";
return 1;
@@ -2412,7 +2497,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args)
return 0;
}
-static bool cmakeCheckStampFile(const std::string& stampName, bool verbose)
+static bool cmakeCheckStampFile(const std::string& stampName)
{
// The stamp file does not exist. Use the stamp dependencies to
// determine whether it is really out of date. This works in
@@ -2435,20 +2520,22 @@ static bool cmakeCheckStampFile(const std::string& stampName, bool verbose)
}
// Compare the stamp dependencies against the dependency file itself.
- cmFileTimeComparison ftc;
- std::string dep;
- while (cmSystemTools::GetLineFromStream(fin, dep)) {
- int result;
- if (!dep.empty() && dep[0] != '#' &&
- (!ftc.FileTimeCompare(stampDepends, dep, &result) || result < 0)) {
- // The stamp depends file is older than this dependency. The
- // build system is really out of date.
- std::cout << "CMake is re-running because " << stampName
- << " is out-of-date.\n";
- std::cout << " the file '" << dep << "'\n";
- std::cout << " is newer than '" << stampDepends << "'\n";
- std::cout << " result='" << result << "'\n";
- return false;
+ {
+ cmFileTimeCache ftc;
+ std::string dep;
+ while (cmSystemTools::GetLineFromStream(fin, dep)) {
+ int result;
+ if (!dep.empty() && dep[0] != '#' &&
+ (!ftc.Compare(stampDepends, dep, &result) || result < 0)) {
+ // The stamp depends file is older than this dependency. The
+ // build system is really out of date.
+ std::cout << "CMake is re-running because " << stampName
+ << " is out-of-date.\n";
+ std::cout << " the file '" << dep << "'\n";
+ std::cout << " is newer than '" << stampDepends << "'\n";
+ std::cout << " result='" << result << "'\n";
+ return false;
+ }
}
}
@@ -2464,21 +2551,15 @@ static bool cmakeCheckStampFile(const std::string& stampName, bool verbose)
stamp << "# CMake generation timestamp file for this directory.\n";
}
if (cmSystemTools::RenameFile(stampTemp, stampName)) {
- if (verbose) {
- // Notify the user why CMake is not re-running. It is safe to
- // just print to stdout here because this code is only reachable
- // through an undocumented flag used by the VS generator.
- std::cout << "CMake does not need to re-run because " << stampName
- << " is up-to-date.\n";
- }
+ // CMake does not need to re-run because the stamp file is up-to-date.
return true;
}
cmSystemTools::RemoveFile(stampTemp);
- cmSystemTools::Error("Cannot restore timestamp ", stampName.c_str());
+ cmSystemTools::Error("Cannot restore timestamp " + stampName);
return false;
}
-static bool cmakeCheckStampList(const std::string& stampList, bool verbose)
+static bool cmakeCheckStampList(const std::string& stampList)
{
// If the stamp list does not exist CMake must rerun to generate it.
if (!cmSystemTools::FileExists(stampList)) {
@@ -2496,7 +2577,7 @@ static bool cmakeCheckStampList(const std::string& stampList, bool verbose)
// Check each stamp.
std::string stampName;
while (cmSystemTools::GetLineFromStream(fin, stampName)) {
- if (!cmakeCheckStampFile(stampName, verbose)) {
+ if (!cmakeCheckStampFile(stampName)) {
return false;
}
}
@@ -2531,7 +2612,8 @@ cmMessenger* cmake::GetMessenger() const
return this->Messenger;
}
-int cmake::Build(int jobs, const std::string& dir, const std::string& target,
+int cmake::Build(int jobs, const std::string& dir,
+ const std::vector<std::string>& targets,
const std::string& config,
const std::vector<std::string>& nativeOptions, bool clean,
bool verbose)
@@ -2617,12 +2699,12 @@ int cmake::Build(int jobs, const std::string& dir, const std::string& target,
}
}
- if (!cmakeCheckStampList(stampList, false)) {
+ if (!cmakeCheckStampList(stampList)) {
// Correctly initialize the home (=source) and home output (=binary)
// directories, which is required for running the generation step.
std::string homeOrig = this->GetHomeDirectory();
std::string homeOutputOrig = this->GetHomeOutputDirectory();
- this->SetDirectoriesFromFile(cachePath.c_str());
+ this->SetDirectoriesFromFile(cachePath);
this->AddProjectCommands();
@@ -2640,7 +2722,7 @@ int cmake::Build(int jobs, const std::string& dir, const std::string& target,
}
std::string message = "Build files have been written to: ";
message += this->GetHomeOutputDirectory();
- this->UpdateProgress(message.c_str(), -1);
+ this->UpdateProgress(message, -1);
// Restore the previously set directories to their original value.
this->SetHomeDirectory(homeOrig);
@@ -2650,9 +2732,8 @@ int cmake::Build(int jobs, const std::string& dir, const std::string& target,
#endif
gen->PrintBuildCommandAdvice(std::cerr, jobs);
-
- return gen->Build(jobs, "", dir, projName, target, output, "", config, clean,
- false, verbose, cmDuration::zero(),
+ return gen->Build(jobs, "", dir, projName, targets, output, "", config,
+ clean, false, verbose, cmDuration::zero(),
cmSystemTools::OUTPUT_PASSTHROUGH, nativeOptions);
}
diff --git a/Source/cmake.h b/Source/cmake.h
index 53d44f148..fa4409aeb 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -26,7 +26,7 @@
class cmExternalMakefileProjectGeneratorFactory;
class cmFileAPI;
-class cmFileTimeComparison;
+class cmFileTimeCache;
class cmGlobalGenerator;
class cmGlobalGeneratorFactory;
class cmMakefile;
@@ -96,6 +96,19 @@ 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
+ };
+
struct GeneratorInfo
{
std::string name;
@@ -123,9 +136,9 @@ public:
#if defined(CMAKE_BUILD_WITH_CMAKE)
Json::Value ReportVersionJson() const;
- Json::Value ReportCapabilitiesJson(bool haveServerMode) const;
+ Json::Value ReportCapabilitiesJson() const;
#endif
- std::string ReportCapabilities(bool haveServerMode) const;
+ std::string ReportCapabilities() const;
//@{
/**
@@ -162,7 +175,7 @@ public:
int Configure();
int ActualConfigure();
- ///! Break up a line like VAR:type="value" into var, type and value
+ //! Break up a line like VAR:type="value" into var, type and value
static bool ParseCacheEntry(const std::string& entry, std::string& var,
std::string& value,
cmStateEnums::CacheEntryType& type);
@@ -176,43 +189,46 @@ public:
bool DeleteCache(const std::string& path);
void PreLoadCMakeFiles();
- ///! Create a GlobalGenerator
+ //! Create a GlobalGenerator
cmGlobalGenerator* CreateGlobalGenerator(const std::string& name);
- ///! Return the global generator assigned to this instance of cmake
+ //! Return the global generator assigned to this instance of cmake
cmGlobalGenerator* GetGlobalGenerator() { return this->GlobalGenerator; }
- ///! Return the global generator assigned to this instance of cmake, const
+ //! Return the global generator assigned to this instance of cmake, const
const cmGlobalGenerator* GetGlobalGenerator() const
{
return this->GlobalGenerator;
}
- ///! Return the full path to where the CMakeCache.txt file should be.
+ //! Return the full path to where the CMakeCache.txt file should be.
static std::string FindCacheFile(const std::string& binaryDir);
- ///! Return the global generator assigned to this instance of cmake
+ //! Return the global generator assigned to this instance of cmake
void SetGlobalGenerator(cmGlobalGenerator*);
- ///! Get the names of the current registered generators
+ //! Get the names of the current registered generators
void GetRegisteredGenerators(std::vector<GeneratorInfo>& generators,
bool includeNamesWithPlatform = true) const;
- ///! Set the name of the selected generator-specific instance.
+ //! Set the name of the selected generator-specific instance.
void SetGeneratorInstance(std::string const& instance)
{
this->GeneratorInstance = instance;
+ this->GeneratorInstanceSet = true;
}
- ///! Set the name of the selected generator-specific platform.
+ //! Set the name of the selected generator-specific platform.
void SetGeneratorPlatform(std::string const& ts)
{
this->GeneratorPlatform = ts;
+ this->GeneratorPlatformSet = true;
}
- ///! Set the name of the selected generator-specific toolset.
+ //! Set the name of the selected generator-specific toolset.
void SetGeneratorToolset(std::string const& ts)
{
this->GeneratorToolset = ts;
+ this->GeneratorToolsetSet = true;
}
const std::vector<std::string>& GetSourceExtensions() const
@@ -244,7 +260,7 @@ public:
* Given a variable name, return its value (as a string).
*/
const char* GetCacheDefinition(const std::string&) const;
- ///! Add an entry into the cache
+ //! Add an entry into the cache
void AddCacheEntry(const std::string& key, const char* value,
const char* helpString, int type);
@@ -263,17 +279,20 @@ public:
*/
int GetSystemInformation(std::vector<std::string>&);
- ///! Parse command line arguments
+ //! Parse environment variables
+ void LoadEnvironmentPresets();
+
+ //! Parse command line arguments
void SetArgs(const std::vector<std::string>& args);
- ///! Is this cmake running as a result of a TRY_COMPILE command
+ //! Is this cmake running as a result of a TRY_COMPILE command
bool GetIsInTryCompile() const;
void SetIsInTryCompile(bool b);
- ///! Parse command line arguments that might set cache values
+ //! Parse command line arguments that might set cache values
bool SetCacheArgs(const std::vector<std::string>&);
- using ProgressCallbackType = std::function<void(const char*, float)>;
+ using ProgressCallbackType = std::function<void(const std::string&, float)>;
/**
* Set the function used by GUIs to receive progress updates
* Function gets passed: message as a const char*, a progress
@@ -283,24 +302,24 @@ public:
*/
void SetProgressCallback(ProgressCallbackType f);
- ///! this is called by generators to update the progress
- void UpdateProgress(const char* msg, float prog);
+ //! this is called by generators to update the progress
+ void UpdateProgress(const std::string& msg, float prog);
#if defined(CMAKE_BUILD_WITH_CMAKE)
- ///! Get the variable watch object
+ //! Get the variable watch object
cmVariableWatch* GetVariableWatch() { return this->VariableWatch; }
#endif
std::vector<cmDocumentationEntry> GetGeneratorsDocumentation();
- ///! Set/Get a property of this target file
+ //! Set/Get a property of this target file
void SetProperty(const std::string& prop, const char* value);
void AppendProperty(const std::string& prop, const char* value,
bool asString = false);
const char* GetProperty(const std::string& prop);
bool GetPropertyAsBool(const std::string& prop);
- ///! Get or create an cmInstalledFile instance and return a pointer to it
+ //! Get or create an cmInstalledFile instance and return a pointer to it
cmInstalledFile* GetOrCreateInstalledFile(cmMakefile* mf,
const std::string& name);
@@ -311,13 +330,13 @@ public:
return this->InstalledFiles;
}
- ///! Do all the checks before running configure
+ //! Do all the checks before running configure
int DoPreConfigureChecks();
void SetWorkingMode(WorkingMode mode) { this->CurrentWorkingMode = mode; }
WorkingMode GetWorkingMode() { return this->CurrentWorkingMode; }
- ///! Debug the try compile stuff by not deleting the files
+ //! Debug the try compile stuff by not deleting the files
bool GetDebugTryCompile() { return this->DebugTryCompile; }
void DebugTryCompileOn() { this->DebugTryCompile = true; }
@@ -329,7 +348,12 @@ public:
/**
* Get the file comparison class
*/
- cmFileTimeComparison* GetFileComparison() { return this->FileComparison; }
+ cmFileTimeCache* GetFileTimeCache() { return this->FileTimeCache; }
+
+ // 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);
// Do we want debug output during the cmake run.
bool GetDebugOutput() { return this->DebugOutput; }
@@ -423,13 +447,13 @@ public:
MessageType t, std::string const& text,
cmListFileBacktrace const& backtrace = cmListFileBacktrace()) const;
- ///! run the --build option
- int Build(int jobs, const std::string& dir, const std::string& target,
- const std::string& config,
+ //! run the --build option
+ int Build(int jobs, const std::string& dir,
+ const std::vector<std::string>& targets, const std::string& config,
const std::vector<std::string>& nativeOptions, bool clean,
bool verbose);
- ///! run the --open option
+ //! run the --open option
bool Open(const std::string& dir, bool dryRun);
void UnwatchUnusedCli(const std::string& var);
@@ -461,13 +485,16 @@ protected:
std::string GeneratorInstance;
std::string GeneratorPlatform;
std::string GeneratorToolset;
+ bool GeneratorInstanceSet;
+ bool GeneratorPlatformSet;
+ bool GeneratorToolsetSet;
- ///! read in a cmake list file to initialize the cache
+ //! read in a cmake list file to initialize the cache
void ReadListFile(const std::vector<std::string>& args,
const std::string& path);
bool FindPackage(const std::vector<std::string>& args);
- ///! Check if CMAKE_CACHEFILE_DIR is set. If it is not, delete the log file.
+ //! Check if CMAKE_CACHEFILE_DIR is set. If it is not, delete the log file.
/// If it is set, truncate it to 50kb
void TruncateOutputLog(const char* fname);
@@ -477,13 +504,13 @@ protected:
*/
int CheckBuildSystem();
- void SetDirectoriesFromFile(const char* arg);
+ void SetDirectoriesFromFile(const std::string& arg);
//! Make sure all commands are what they say they are and there is no
/// macros.
void CleanupCommandsAndMacros();
- void GenerateGraphViz(const char* fileName) const;
+ void GenerateGraphViz(const std::string& fileName) const;
private:
ProgressCallbackType ProgressCallback;
@@ -503,13 +530,14 @@ private:
std::string CheckStampFile;
std::string CheckStampList;
std::string VSSolutionFile;
+ std::string EnvironmentGenerator;
std::vector<std::string> SourceFileExtensions;
std::unordered_set<std::string> SourceFileExtensionsSet;
std::vector<std::string> HeaderFileExtensions;
std::unordered_set<std::string> HeaderFileExtensionsSet;
bool ClearBuildSystem;
bool DebugTryCompile;
- cmFileTimeComparison* FileComparison;
+ cmFileTimeCache* FileTimeCache;
std::string GraphVizFile;
InstalledFilesMap InstalledFiles;
@@ -524,6 +552,8 @@ private:
std::vector<std::string> TraceOnlyThisSources;
+ LogLevel MessageLogLevel = LogLevel::LOG_STATUS;
+
void UpdateConversionPathTable();
// Print a list of valid generators to stderr.
@@ -562,40 +592,38 @@ private:
"not errors." \
}
+#define FOR_EACH_C90_FEATURE(F) F(c_function_prototypes)
+
+#define FOR_EACH_C99_FEATURE(F) \
+ F(c_restrict) \
+ F(c_variadic_macros)
+
+#define FOR_EACH_C11_FEATURE(F) F(c_static_assert)
+
#define FOR_EACH_C_FEATURE(F) \
F(c_std_90) \
F(c_std_99) \
F(c_std_11) \
- F(c_function_prototypes) \
- F(c_restrict) \
- F(c_static_assert) \
- F(c_variadic_macros)
+ FOR_EACH_C90_FEATURE(F) \
+ FOR_EACH_C99_FEATURE(F) \
+ FOR_EACH_C11_FEATURE(F)
-#define FOR_EACH_CXX_FEATURE(F) \
- F(cxx_std_98) \
- F(cxx_std_11) \
- F(cxx_std_14) \
- F(cxx_std_17) \
- F(cxx_std_20) \
- F(cxx_aggregate_default_initializers) \
+#define FOR_EACH_CXX98_FEATURE(F) F(cxx_template_template_parameters)
+
+#define FOR_EACH_CXX11_FEATURE(F) \
F(cxx_alias_templates) \
F(cxx_alignas) \
F(cxx_alignof) \
F(cxx_attributes) \
- F(cxx_attribute_deprecated) \
F(cxx_auto_type) \
- F(cxx_binary_literals) \
F(cxx_constexpr) \
- F(cxx_contextual_conversions) \
F(cxx_decltype) \
- F(cxx_decltype_auto) \
F(cxx_decltype_incomplete_return_types) \
F(cxx_default_function_template_args) \
F(cxx_defaulted_functions) \
F(cxx_defaulted_move_initializers) \
F(cxx_delegating_constructors) \
F(cxx_deleted_functions) \
- F(cxx_digit_separators) \
F(cxx_enum_forward_declarations) \
F(cxx_explicit_conversions) \
F(cxx_extended_friend_declarations) \
@@ -603,11 +631,9 @@ private:
F(cxx_final) \
F(cxx_func_identifier) \
F(cxx_generalized_initializers) \
- F(cxx_generic_lambdas) \
F(cxx_inheriting_constructors) \
F(cxx_inline_namespaces) \
F(cxx_lambdas) \
- F(cxx_lambda_init_captures) \
F(cxx_local_type_template_args) \
F(cxx_long_long_type) \
F(cxx_noexcept) \
@@ -617,22 +643,41 @@ private:
F(cxx_range_for) \
F(cxx_raw_string_literals) \
F(cxx_reference_qualified_functions) \
- F(cxx_relaxed_constexpr) \
- F(cxx_return_type_deduction) \
F(cxx_right_angle_brackets) \
F(cxx_rvalue_references) \
F(cxx_sizeof_member) \
F(cxx_static_assert) \
F(cxx_strong_enums) \
- F(cxx_template_template_parameters) \
F(cxx_thread_local) \
F(cxx_trailing_return_types) \
F(cxx_unicode_literals) \
F(cxx_uniform_initialization) \
F(cxx_unrestricted_unions) \
F(cxx_user_literals) \
- F(cxx_variable_templates) \
F(cxx_variadic_macros) \
F(cxx_variadic_templates)
+#define FOR_EACH_CXX14_FEATURE(F) \
+ F(cxx_aggregate_default_initializers) \
+ F(cxx_attribute_deprecated) \
+ F(cxx_binary_literals) \
+ F(cxx_contextual_conversions) \
+ F(cxx_decltype_auto) \
+ F(cxx_digit_separators) \
+ F(cxx_generic_lambdas) \
+ F(cxx_lambda_init_captures) \
+ F(cxx_relaxed_constexpr) \
+ F(cxx_return_type_deduction) \
+ F(cxx_variable_templates)
+
+#define FOR_EACH_CXX_FEATURE(F) \
+ F(cxx_std_98) \
+ F(cxx_std_11) \
+ F(cxx_std_14) \
+ F(cxx_std_17) \
+ F(cxx_std_20) \
+ FOR_EACH_CXX98_FEATURE(F) \
+ FOR_EACH_CXX11_FEATURE(F) \
+ FOR_EACH_CXX14_FEATURE(F)
+
#endif
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index a83f7dc8b..a6348b39e 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -23,6 +23,8 @@
# include "cmsys/ConsoleBuf.hxx"
#endif
+#include <cassert>
+#include <climits>
#include <ctype.h>
#include <iostream>
#include <string.h>
@@ -54,29 +56,38 @@ static const char* cmDocumentationUsageNote[][2] = {
# define CMAKE_BUILD_OPTIONS \
" <dir> = Project binary directory to be built.\n" \
- " -j [<jobs>] --parallel [<jobs>] = Build in parallel using\n" \
- " the given number of jobs. If <jobs> is omitted\n" \
- " the native build tool's default number is used.\n" \
+ " --parallel [<jobs>], -j [<jobs>]\n" \
+ " = Build in parallel using the given number of jobs. \n" \
+ " If <jobs> is omitted the native build tool's \n" \
+ " default number is used.\n" \
" The CMAKE_BUILD_PARALLEL_LEVEL environment " \
"variable\n" \
" specifies a default parallel level when this " \
"option\n" \
" is not given.\n" \
- " --target <tgt> = Build <tgt> instead of default targets.\n" \
- " May only be specified once.\n" \
+ " --target <tgt>..., -t <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" \
- " --use-stderr = Ignored. Behavior is default in CMake >= 3.0.\n" \
- " -v --verbose = Enable verbose output - if supported - including\n" \
+ " --verbose, -v = Enable verbose output - if supported - including\n" \
" the build commands to be executed. \n" \
" -- = Pass remaining options to the native tool.\n"
+# define CMAKE_INSTALL_OPTIONS \
+ " <dir> = Project binary directory to install.\n" \
+ " --config <cfg> = For multi-configuration tools, choose <cfg>.\n" \
+ " --component <comp> = Component-based install. Only install <comp>.\n" \
+ " --prefix <prefix> = The installation prefix CMAKE_INSTALL_PREFIX.\n" \
+ " --strip = Performing install/strip.\n" \
+ " -v --verbose = Enable verbose output.\n"
+
static const char* cmDocumentationOptions[][2] = {
CMAKE_STANDARD_OPTIONS_TABLE,
{ "-E", "CMake command mode." },
{ "-L[A][H]", "List non-advanced cached variables." },
{ "--build <dir>", "Build a CMake-generated project binary tree." },
+ { "--install <dir>", "Install a CMake-generated project binary tree." },
{ "--open <dir>", "Open generated project in the associated application." },
{ "-N", "View mode only." },
{ "-P <file>", "Process script mode." },
@@ -85,6 +96,8 @@ static const char* cmDocumentationOptions[][2] = {
"Generate graphviz of dependencies, see "
"CMakeGraphVizOptions.cmake for more." },
{ "--system-information [file]", "Dump information about this system." },
+ { "--loglevel=<ERROR|WARNING|NOTICE|STATUS|VERBOSE|DEBUG|TRACE>",
+ "Set the verbosity of messages from CMake files." },
{ "--debug-trycompile",
"Do not delete the try_compile build tree. Only "
"useful on one try_compile at a time." },
@@ -109,12 +122,13 @@ static int do_command(int ac, char const* const* av)
std::vector<std::string> args;
args.reserve(ac - 1);
args.emplace_back(av[0]);
- args.insert(args.end(), av + 2, av + ac);
+ cmAppend(args, av + 2, av + ac);
return cmcmd::ExecuteCMakeCommand(args);
}
int do_cmake(int ac, char const* const* av);
static int do_build(int ac, char const* const* av);
+static int do_install(int ac, char const* const* av);
static int do_open(int ac, char const* const* av);
static cmMakefile* cmakemainGetMakefile(cmake* cm)
@@ -142,20 +156,21 @@ static std::string cmakemainGetStack(cmake* cm)
return msg;
}
-static void cmakemainMessageCallback(const char* m, const char* /*unused*/,
- cmake* cm)
+static void cmakemainMessageCallback(const std::string& m,
+ const char* /*unused*/, cmake* cm)
{
std::cerr << m << cmakemainGetStack(cm) << std::endl << std::flush;
}
-static void cmakemainProgressCallback(const char* m, float prog, cmake* cm)
+static void cmakemainProgressCallback(const std::string& m, float prog,
+ cmake* cm)
{
cmMakefile* mf = cmakemainGetMakefile(cm);
std::string dir;
- if ((mf) && (strstr(m, "Configuring") == m) && (prog < 0)) {
+ if (mf && cmHasLiteralPrefix(m, "Configuring") && (prog < 0)) {
dir = " ";
dir += mf->GetCurrentSourceDirectory();
- } else if ((mf) && (strstr(m, "Generating") == m)) {
+ } else if (mf && cmHasLiteralPrefix(m, "Generating")) {
dir = " ";
dir += mf->GetCurrentBinaryDirectory();
}
@@ -169,6 +184,7 @@ static void cmakemainProgressCallback(const char* m, float prog, cmake* cm)
int main(int ac, char const* const* av)
{
+ cmSystemTools::EnsureStdPipes();
#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
// Replace streambuf so we can output Unicode to console
cmsys::ConsoleBuf::Manager consoleOut(std::cout);
@@ -188,6 +204,9 @@ int main(int ac, char const* const* av)
if (strcmp(av[1], "--build") == 0) {
return do_build(ac, av);
}
+ if (strcmp(av[1], "--install") == 0) {
+ return do_install(ac, av);
+ }
if (strcmp(av[1], "--open") == 0) {
return do_open(ac, av);
}
@@ -319,10 +338,11 @@ int do_cmake(int ac, char const* const* av)
cmake cm(role, mode);
cm.SetHomeDirectory("");
cm.SetHomeOutputDirectory("");
- cmSystemTools::SetMessageCallback([&cm](const char* msg, const char* title) {
- cmakemainMessageCallback(msg, title, &cm);
- });
- cm.SetProgressCallback([&cm](const char* msg, float prog) {
+ cmSystemTools::SetMessageCallback(
+ [&cm](const std::string& msg, const char* title) {
+ cmakemainMessageCallback(msg, title, &cm);
+ });
+ cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
cmakemainProgressCallback(msg, prog, &cm);
});
cm.SetWorkingMode(workingMode);
@@ -377,7 +397,14 @@ int extract_job_number(int& index, char const* current, char const* next,
if (jobString.empty()) {
jobs = cmake::DEFAULT_BUILD_PARALLEL_LEVEL;
} else if (cmSystemTools::StringToULong(jobString.c_str(), &numJobs)) {
- jobs = int(numJobs);
+ if (numJobs == 0) {
+ std::cerr
+ << "The <jobs> value requires a positive integer argument.\n\n";
+ } else if (numJobs > INT_MAX) {
+ std::cerr << "The <jobs> value is too large.\n\n";
+ } else {
+ jobs = int(numJobs);
+ }
} else {
std::cerr << "'" << command.substr(0, len_of_flag) << "' invalid number '"
<< jobString << "' given.\n\n";
@@ -393,13 +420,14 @@ static int do_build(int ac, char const* const* av)
return -1;
#else
int jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
- std::string target;
+ std::vector<std::string> targets;
std::string config = "Debug";
std::string dir;
std::vector<std::string> nativeOptions;
- bool clean = false;
+ bool cleanFirst = false;
+ bool foundClean = false;
+ bool foundNonClean = false;
bool verbose = cmSystemTools::HasEnv("VERBOSE");
- bool hasTarget = false;
enum Doing
{
@@ -419,25 +447,21 @@ static int do_build(int ac, char const* const* av)
if (jobs < 0) {
dir.clear();
}
+ doing = DoingNone;
} else if (cmHasLiteralPrefix(av[i], "--parallel")) {
const char* nextArg = ((i + 1 < ac) ? av[i + 1] : nullptr);
jobs = extract_job_number(i, av[i], nextArg, sizeof("--parallel") - 1);
if (jobs < 0) {
dir.clear();
}
- } else if (strcmp(av[i], "--target") == 0) {
- if (!hasTarget) {
- doing = DoingTarget;
- hasTarget = true;
- } else {
- std::cerr << "'--target' may not be specified more than once.\n\n";
- dir.clear();
- break;
- }
+ doing = DoingNone;
+ } else if ((strcmp(av[i], "--target") == 0) ||
+ (strcmp(av[i], "-t") == 0)) {
+ doing = DoingTarget;
} else if (strcmp(av[i], "--config") == 0) {
doing = DoingConfig;
} else if (strcmp(av[i], "--clean-first") == 0) {
- clean = true;
+ cleanFirst = true;
doing = DoingNone;
} else if ((strcmp(av[i], "--verbose") == 0) ||
(strcmp(av[i], "-v") == 0)) {
@@ -454,8 +478,23 @@ static int do_build(int ac, char const* const* av)
doing = DoingNone;
break;
case DoingTarget:
- target = av[i];
- doing = DoingNone;
+ if (strlen(av[i]) == 0) {
+ std::cerr << "Warning: Argument number " << i
+ << " after --target option is empty." << std::endl;
+ } else {
+ targets.emplace_back(av[i]);
+ if (strcmp(av[i], "clean") == 0) {
+ foundClean = true;
+ } else {
+ foundNonClean = true;
+ }
+ }
+ if (foundClean && foundNonClean) {
+ std::cerr << "Error: Building 'clean' and other targets together "
+ "is not supported."
+ << std::endl;
+ dir.clear();
+ }
break;
case DoingConfig:
config = av[i];
@@ -477,7 +516,17 @@ static int do_build(int ac, char const* const* av)
} else {
unsigned long numJobs = 0;
if (cmSystemTools::StringToULong(parallel.c_str(), &numJobs)) {
- jobs = int(numJobs);
+ if (numJobs == 0) {
+ std::cerr << "The CMAKE_BUILD_PARALLEL_LEVEL environment variable "
+ "requires a positive integer argument.\n\n";
+ dir.clear();
+ } else if (numJobs > INT_MAX) {
+ std::cerr << "The CMAKE_BUILD_PARALLEL_LEVEL environment variable "
+ "is too large.\n\n";
+ dir.clear();
+ } else {
+ jobs = int(numJobs);
+ }
} else {
std::cerr << "'CMAKE_BUILD_PARALLEL_LEVEL' environment variable\n"
<< "invalid number '" << parallel << "' given.\n\n";
@@ -499,13 +548,126 @@ static int do_build(int ac, char const* const* av)
}
cmake cm(cmake::RoleInternal, cmState::Project);
- cmSystemTools::SetMessageCallback([&cm](const char* msg, const char* title) {
- cmakemainMessageCallback(msg, title, &cm);
+ cmSystemTools::SetMessageCallback(
+ [&cm](const std::string& msg, const char* title) {
+ cmakemainMessageCallback(msg, title, &cm);
+ });
+ cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
+ cmakemainProgressCallback(msg, prog, &cm);
});
- cm.SetProgressCallback([&cm](const char* msg, float prog) {
+ return cm.Build(jobs, dir, targets, config, nativeOptions, cleanFirst,
+ verbose);
+#endif
+}
+
+static int do_install(int ac, char const* const* av)
+{
+#ifndef CMAKE_BUILD_WITH_CMAKE
+ std::cerr << "This cmake does not support --install\n";
+ return -1;
+#else
+ assert(1 < ac);
+
+ std::string config;
+ std::string component;
+ std::string prefix;
+ std::string dir;
+ bool strip = false;
+ bool verbose = cmSystemTools::HasEnv("VERBOSE");
+
+ enum Doing
+ {
+ DoingNone,
+ DoingDir,
+ DoingConfig,
+ DoingComponent,
+ DoingPrefix,
+ };
+
+ Doing doing = DoingDir;
+
+ for (int i = 2; i < ac; ++i) {
+ if (strcmp(av[i], "--config") == 0) {
+ doing = DoingConfig;
+ } else if (strcmp(av[i], "--component") == 0) {
+ doing = DoingComponent;
+ } else if (strcmp(av[i], "--prefix") == 0) {
+ doing = DoingPrefix;
+ } else if (strcmp(av[i], "--strip") == 0) {
+ strip = true;
+ doing = DoingNone;
+ } else if ((strcmp(av[i], "--verbose") == 0) ||
+ (strcmp(av[i], "-v") == 0)) {
+ verbose = true;
+ doing = DoingNone;
+ } else {
+ switch (doing) {
+ case DoingDir:
+ dir = cmSystemTools::CollapseFullPath(av[i]);
+ doing = DoingNone;
+ break;
+ case DoingConfig:
+ config = av[i];
+ doing = DoingNone;
+ break;
+ case DoingComponent:
+ component = av[i];
+ doing = DoingNone;
+ break;
+ case DoingPrefix:
+ prefix = av[i];
+ doing = DoingNone;
+ break;
+ default:
+ std::cerr << "Unknown argument " << av[i] << std::endl;
+ dir.clear();
+ break;
+ }
+ }
+ }
+
+ if (dir.empty()) {
+ std::cerr << "Usage: cmake --install <dir> "
+ "[options]\nOptions:\n" CMAKE_INSTALL_OPTIONS;
+ return 1;
+ }
+
+ cmake cm(cmake::RoleScript, cmState::Script);
+
+ cmSystemTools::SetMessageCallback(
+ [&cm](const std::string& msg, const char* title) {
+ cmakemainMessageCallback(msg, title, &cm);
+ });
+ cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
cmakemainProgressCallback(msg, prog, &cm);
});
- return cm.Build(jobs, dir, target, config, nativeOptions, clean, verbose);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.SetDebugOutputOn(verbose);
+ cm.SetWorkingMode(cmake::SCRIPT_MODE);
+
+ std::vector<std::string> args{ av[0] };
+
+ if (!prefix.empty()) {
+ args.emplace_back("-DCMAKE_INSTALL_PREFIX=" + prefix);
+ }
+
+ if (!component.empty()) {
+ args.emplace_back("-DCMAKE_INSTALL_COMPONENT=" + component);
+ }
+
+ if (strip) {
+ args.emplace_back("-DCMAKE_INSTALL_DO_STRIP=1");
+ }
+
+ if (!config.empty()) {
+ args.emplace_back("-DCMAKE_INSTALL_CONFIG_NAME=" + config);
+ }
+
+ args.emplace_back("-P");
+ args.emplace_back(dir + "/cmake_install.cmake");
+
+ return cm.Run(args) ? 1 : 0;
#endif
}
@@ -541,10 +703,11 @@ static int do_open(int ac, char const* const* av)
}
cmake cm(cmake::RoleInternal, cmState::Unknown);
- cmSystemTools::SetMessageCallback([&cm](const char* msg, const char* title) {
- cmakemainMessageCallback(msg, title, &cm);
- });
- cm.SetProgressCallback([&cm](const char* msg, float prog) {
+ cmSystemTools::SetMessageCallback(
+ [&cm](const std::string& msg, const char* title) {
+ cmakemainMessageCallback(msg, title, &cm);
+ });
+ cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
cmakemainProgressCallback(msg, prog, &cm);
});
return cm.Open(dir, false) ? 0 : 1;
diff --git a/Source/cmakexbuild.cxx b/Source/cmakexbuild.cxx
deleted file mode 100644
index 295194595..000000000
--- a/Source/cmakexbuild.cxx
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include "cmsys/Process.h"
-#include <iostream>
-#include <string>
-#include <vector>
-
-#include "cmDuration.h"
-#include "cmSystemTools.h"
-
-// This is a wrapper program for xcodebuild
-// it calls xcodebuild, and does two things
-// it removes much of the output, all the setenv
-// stuff. Also, it checks for the text file busy
-// error, and re-runs xcodebuild until that error does
-// not show up.
-
-int RunXCode(std::vector<const char*>& argv, bool& hitbug)
-{
- hitbug = false;
- cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, &*argv.begin());
- cmsysProcess_SetTimeout(cp, 0);
- cmsysProcess_Execute(cp);
- std::vector<char> out;
- std::vector<char> err;
- std::string line;
- int pipe =
- cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, err);
- while (pipe != cmsysProcess_Pipe_None) {
- if (line.find("/bin/sh: bad interpreter: Text file busy") !=
- std::string::npos) {
- hitbug = true;
- std::cerr << "Hit xcodebuild bug : " << line << "\n";
- }
- // if the bug is hit, no more output should be generated
- // because it may contain bogus errors
- // also remove all output with setenv in it to tone down
- // the verbosity of xcodebuild
- if (!hitbug && (line.find("setenv") == std::string::npos)) {
- if (pipe == cmsysProcess_Pipe_STDERR) {
- std::cerr << line << "\n";
- } else if (pipe == cmsysProcess_Pipe_STDOUT) {
- std::cout << line << "\n";
- }
- }
- pipe = cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out,
- err);
- }
- cmsysProcess_WaitForExit(cp, nullptr);
- if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
- return cmsysProcess_GetExitValue(cp);
- }
- if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
- return -1;
- }
- return -1;
-}
-
-int main(int ac, char* av[])
-{
- std::vector<const char*> argv;
- argv.push_back("xcodebuild");
- for (int i = 1; i < ac; i++) {
- argv.push_back(av[i]);
- }
- argv.push_back(nullptr);
- bool hitbug = true;
- int ret = 0;
- while (hitbug) {
- ret = RunXCode(argv, hitbug);
- }
- if (ret < 0) {
- return 255;
- }
- return ret;
-}
diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx
index 1a10666c5..19d0d3843 100644
--- a/Source/cmcldeps.cxx
+++ b/Source/cmcldeps.cxx
@@ -276,7 +276,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 d20c5d23a..86082e517 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -7,8 +7,9 @@
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
-#include "cmQtAutoGeneratorMocUic.h"
-#include "cmQtAutoGeneratorRcc.h"
+#include "cmQtAutoMocUic.h"
+#include "cmQtAutoRcc.h"
+#include "cmRange.h"
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
@@ -37,6 +38,7 @@
#include "cmsys/Process.h"
#include "cmsys/Terminal.h"
#include <algorithm>
+#include <array>
#include <iostream>
#include <iterator>
#include <memory> // IWYU pragma: keep
@@ -101,7 +103,7 @@ void CMakeCommandUsage(const char* program)
<< " sha512sum <file>... - create SHA512 checksum of files\n"
<< " remove [-f] <file>... - remove the file(s), use -f to force "
"it\n"
- << " remove_directory dir - remove a directory and its contents\n"
+ << " remove_directory <dir>... - remove directories and their contents\n"
<< " rename oldname newname - rename a file or directory "
"(on one volume)\n"
<< " server - start cmake in server mode\n"
@@ -109,8 +111,8 @@ void CMakeCommandUsage(const char* program)
<< " tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n"
<< " - create or extract a tar or zip archive\n"
<< " time command [args...] - run command and display elapsed time\n"
- << " touch file - touch a file.\n"
- << " touch_nocreate file - touch a file but do not create it.\n"
+ << " touch <file>... - touch a <file>.\n"
+ << " touch_nocreate <file>... - touch a <file> but do not create it.\n"
<< " create_symlink old new - create a symbolic link new -> old\n"
#if defined(_WIN32) && !defined(__CYGWIN__)
<< "Available on Windows only:\n"
@@ -171,7 +173,7 @@ static int HandleIWYU(const std::string& runCmd,
// and adding all the arguments we give to the compiler.
std::vector<std::string> iwyu_cmd;
cmSystemTools::ExpandListArgument(runCmd, iwyu_cmd, true);
- iwyu_cmd.insert(iwyu_cmd.end(), orig_cmd.begin() + 1, orig_cmd.end());
+ cmAppend(iwyu_cmd, orig_cmd.begin() + 1, orig_cmd.end());
// Run the iwyu command line. Capture its stderr and hide its stdout.
// Ignore its return code because the tool always returns non-zero.
std::string stdErr;
@@ -199,11 +201,11 @@ static int HandleTidy(const std::string& runCmd, const std::string& sourceFile,
// automatically skip over the compiler itself and extract the
// options.
int ret;
- std::vector<std::string> tidy_cmd;
- cmSystemTools::ExpandListArgument(runCmd, tidy_cmd, true);
+ std::vector<std::string> tidy_cmd =
+ cmSystemTools::ExpandedListArgument(runCmd, true);
tidy_cmd.push_back(sourceFile);
tidy_cmd.emplace_back("--");
- tidy_cmd.insert(tidy_cmd.end(), orig_cmd.begin(), orig_cmd.end());
+ cmAppend(tidy_cmd, orig_cmd);
// Run the tidy command line. Capture its stdout and hide its stderr.
std::string stdOut;
@@ -350,12 +352,13 @@ struct CoCompiler
bool NoOriginalCommand;
};
-static CoCompiler CoCompilers[] = { // Table of options and handlers.
- { "--cppcheck=", HandleCppCheck, false },
- { "--cpplint=", HandleCppLint, false },
- { "--iwyu=", HandleIWYU, false },
- { "--lwyu=", HandleLWYU, true },
- { "--tidy=", HandleTidy, false }
+static const std::array<CoCompiler, 5> CoCompilers = {
+ { // Table of options and handlers.
+ { "--cppcheck=", HandleCppCheck, false },
+ { "--cpplint=", HandleCppLint, false },
+ { "--iwyu=", HandleIWYU, false },
+ { "--lwyu=", HandleLWYU, true },
+ { "--tidy=", HandleTidy, false } }
};
struct CoCompileJob
@@ -365,7 +368,7 @@ struct CoCompileJob
};
// called when args[0] == "__run_co_compile"
-int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args)
+int cmcmd::HandleCoCompileCommands(std::vector<std::string> const& args)
{
std::vector<CoCompileJob> jobs;
std::string sourceFile; // store --source=
@@ -378,24 +381,22 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args)
std::vector<std::string> orig_cmd;
bool doing_options = true;
- for (std::string::size_type i = 2; i < args.size(); ++i) {
- std::string const& arg = args[i];
+ for (std::string const& arg : cmMakeRange(args).advance(2)) {
// if the arg is -- then the rest of the args after
// go into orig_cmd
if (arg == "--") {
doing_options = false;
} else if (doing_options) {
bool optionFound = false;
- for (CoCompiler const* cc = cm::cbegin(CoCompilers);
- cc != cm::cend(CoCompilers); ++cc) {
- size_t optionLen = strlen(cc->Option);
- if (arg.compare(0, optionLen, cc->Option) == 0) {
+ for (CoCompiler const& cc : CoCompilers) {
+ size_t optionLen = strlen(cc.Option);
+ if (arg.compare(0, optionLen, cc.Option) == 0) {
optionFound = true;
CoCompileJob job;
job.Command = arg.substr(optionLen);
- job.Handler = cc->Handler;
+ job.Handler = cc.Handler;
jobs.push_back(std::move(job));
- if (cc->NoOriginalCommand) {
+ if (cc.NoOriginalCommand) {
runOriginalCmd = false;
}
}
@@ -419,9 +420,8 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args)
if (jobs.empty()) {
std::cerr << "__run_co_compile missing command to run. "
"Looking for one or more of the following:\n";
- for (CoCompiler const* cc = cm::cbegin(CoCompilers);
- cc != cm::cend(CoCompilers); ++cc) {
- std::cerr << cc->Option << "\n";
+ for (CoCompiler const& cc : CoCompilers) {
+ std::cerr << cc.Option << "\n";
}
return 1;
}
@@ -465,7 +465,7 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args)
return ret;
}
-int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
+int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args)
{
// IF YOU ADD A NEW COMMAND, DOCUMENT IT ABOVE and in cmakemain.cxx
if (args.size() > 1) {
@@ -481,9 +481,9 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
}
// If error occurs we want to continue copying next files.
bool return_value = false;
- for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) {
- if (!cmSystemTools::cmCopyFile(args[cc], args.back())) {
- std::cerr << "Error copying file \"" << args[cc] << "\" to \""
+ for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
+ if (!cmsys::SystemTools::CopyFileAlways(arg, args.back())) {
+ std::cerr << "Error copying file \"" << arg << "\" to \""
<< args.back() << "\".\n";
return_value = true;
}
@@ -503,9 +503,9 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
}
// If error occurs we want to continue copying next files.
bool return_value = false;
- for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) {
- if (!cmSystemTools::CopyFileIfDifferent(args[cc], args.back())) {
- std::cerr << "Error copying file (if different) from \"" << args[cc]
+ for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
+ if (!cmSystemTools::CopyFileIfDifferent(arg, args.back())) {
+ std::cerr << "Error copying file (if different) from \"" << arg
<< "\" to \"" << args.back() << "\".\n";
return_value = true;
}
@@ -517,10 +517,10 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
if (args[1] == "copy_directory" && args.size() > 3) {
// If error occurs we want to continue copying next files.
bool return_value = false;
- for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) {
- if (!cmSystemTools::CopyADirectory(args[cc], args.back())) {
- std::cerr << "Error copying directory from \"" << args[cc]
- << "\" to \"" << args.back() << "\".\n";
+ for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
+ if (!cmSystemTools::CopyADirectory(arg, args.back())) {
+ std::cerr << "Error copying directory from \"" << arg << "\" to \""
+ << args.back() << "\".\n";
return_value = true;
}
}
@@ -613,13 +613,13 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
}
if (args[1] == "env") {
- std::vector<std::string>::const_iterator ai = args.begin() + 2;
- std::vector<std::string>::const_iterator ae = args.end();
+ auto ai = args.cbegin() + 2;
+ auto ae = args.cend();
for (; ai != ae; ++ai) {
std::string const& a = *ai;
if (cmHasLiteralPrefix(a, "--unset=")) {
// Unset environment variable.
- cmSystemTools::UnPutEnv(a.c_str() + 8);
+ cmSystemTools::UnPutEnv(a.substr(8));
} else if (!a.empty() && a[0] == '-') {
// Environment variable and command names cannot start in '-',
// so this must be an unknown option.
@@ -653,47 +653,49 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
#if defined(CMAKE_BUILD_WITH_CMAKE)
if (args[1] == "environment") {
- std::vector<std::string> env = cmSystemTools::GetEnvironmentVariables();
- std::vector<std::string>::iterator it;
- for (it = env.begin(); it != env.end(); ++it) {
- std::cout << *it << std::endl;
+ for (auto const& env : cmSystemTools::GetEnvironmentVariables()) {
+ std::cout << env << std::endl;
}
return 0;
}
#endif
if (args[1] == "make_directory" && args.size() > 2) {
- // If error occurs we want to continue copying next files.
+ // If an error occurs, we want to continue making directories.
bool return_value = false;
- for (std::string::size_type cc = 2; cc < args.size(); cc++) {
- if (!cmSystemTools::MakeDirectory(args[cc])) {
- std::cerr << "Error creating directory \"" << args[cc] << "\".\n";
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (!cmSystemTools::MakeDirectory(arg)) {
+ std::cerr << "Error creating directory \"" << arg << "\".\n";
return_value = true;
}
}
return return_value;
}
- if (args[1] == "remove_directory" && args.size() == 3) {
- if (cmSystemTools::FileIsDirectory(args[2]) &&
- !cmSystemTools::RemoveADirectory(args[2])) {
- std::cerr << "Error removing directory \"" << args[2] << "\".\n";
- return 1;
+ if (args[1] == "remove_directory" && args.size() > 2) {
+ // If an error occurs, we want to continue removing directories.
+ bool return_value = false;
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (cmSystemTools::FileIsDirectory(arg) &&
+ !cmSystemTools::RemoveADirectory(arg)) {
+ std::cerr << "Error removing directory \"" << arg << "\".\n";
+ return_value = true;
+ }
}
- return 0;
+ return return_value;
}
// Remove file
if (args[1] == "remove" && args.size() > 2) {
bool force = false;
- for (std::string::size_type cc = 2; cc < args.size(); cc++) {
- if (args[cc] == "\\-f" || args[cc] == "-f") {
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (arg == "\\-f" || arg == "-f") {
force = true;
} else {
// Complain if the file could not be removed, still exists,
// and the -f option was not given.
- if (!cmSystemTools::RemoveFile(args[cc]) && !force &&
- cmSystemTools::FileExists(args[cc])) {
+ if (!cmSystemTools::RemoveFile(arg) && !force &&
+ cmSystemTools::FileExists(arg)) {
return 1;
}
}
@@ -703,10 +705,10 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
// Touch file
if (args[1] == "touch" && args.size() > 2) {
- for (std::string::size_type cc = 2; cc < args.size(); cc++) {
- if (!cmSystemTools::Touch(args[cc], true)) {
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (!cmSystemTools::Touch(arg, true)) {
std::cerr << "cmake -E touch: failed to update \"";
- std::cerr << args[cc] << "\".\n";
+ std::cerr << arg << "\".\n";
return 1;
}
}
@@ -715,10 +717,10 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
// Touch file
if (args[1] == "touch_nocreate" && args.size() > 2) {
- for (std::string::size_type cc = 2; cc < args.size(); cc++) {
- if (!cmSystemTools::Touch(args[cc], false)) {
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (!cmSystemTools::Touch(arg, false)) {
std::cerr << "cmake -E touch_nocreate: failed to update \"";
- std::cerr << args[cc] << "\".\n";
+ std::cerr << arg << "\".\n";
return 1;
}
}
@@ -732,26 +734,22 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
return 1;
}
cmake cm(cmake::RoleInternal, cmState::Unknown);
-#if defined(CMAKE_BUILD_WITH_CMAKE)
- std::cout << cm.ReportCapabilities(true);
-#else
- std::cout << cm.ReportCapabilities(false);
-#endif
+ std::cout << cm.ReportCapabilities();
return 0;
}
// Sleep command
if (args[1] == "sleep" && args.size() > 2) {
double total = 0;
- for (size_t i = 2; i < args.size(); ++i) {
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
double num = 0.0;
char unit;
char extra;
- int n = sscanf(args[i].c_str(), "%lg%c%c", &num, &unit, &extra);
+ int n = sscanf(arg.c_str(), "%lg%c%c", &num, &unit, &extra);
if ((n == 1 || (n == 2 && unit == 's')) && num >= 0) {
total += num;
} else {
- std::cerr << "Unknown sleep time format \"" << args[i] << "\".\n";
+ std::cerr << "Unknown sleep time format \"" << arg << "\".\n";
return 1;
}
}
@@ -817,8 +815,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
if (args[1] == "chdir" && args.size() >= 4) {
std::string const& directory = args[2];
if (!cmSystemTools::FileExists(directory)) {
- cmSystemTools::Error("Directory does not exist for chdir command: ",
- args[2].c_str());
+ cmSystemTools::Error("Directory does not exist for chdir command: " +
+ args[2]);
return 1;
}
@@ -826,7 +824,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
cmWrap('"', cmMakeRange(args).advance(3), '"', " ");
int retval = 0;
if (cmSystemTools::RunSingleCommand(
- command.c_str(), nullptr, nullptr, &retval, directory.c_str(),
+ command, nullptr, nullptr, &retval, directory.c_str(),
cmSystemTools::OUTPUT_PASSTHROUGH, cmDuration::zero())) {
return retval;
}
@@ -1020,13 +1018,13 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
#ifdef CMAKE_BUILD_WITH_CMAKE
if ((args[1] == "cmake_autogen") && (args.size() >= 4)) {
- cmQtAutoGeneratorMocUic autoGen;
+ cmQtAutoMocUic autoGen;
std::string const& infoDir = args[2];
std::string const& config = args[3];
return autoGen.Run(infoDir, config) ? 0 : 1;
}
if ((args[1] == "cmake_autorcc") && (args.size() >= 3)) {
- cmQtAutoGeneratorRcc autoGen;
+ cmQtAutoRcc autoGen;
std::string const& infoFile = args[2];
std::string config;
if (args.size() > 3) {
@@ -1045,12 +1043,17 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
std::vector<std::string> files;
std::string mtime;
std::string format;
+ cmSystemTools::cmTarCompression compress =
+ cmSystemTools::TarCompressNone;
+ int nCompress = 0;
bool doing_options = true;
- for (std::string::size_type cc = 4; cc < args.size(); cc++) {
- std::string const& arg = args[cc];
+ for (auto const& arg : cmMakeRange(args).advance(4)) {
if (doing_options && cmHasLiteralPrefix(arg, "--")) {
if (arg == "--") {
doing_options = false;
+ } else if (arg == "--zstd") {
+ compress = cmSystemTools::TarCompressZstd;
+ ++nCompress;
} else if (cmHasLiteralPrefix(arg, "--mtime=")) {
mtime = arg.substr(8);
} else if (cmHasLiteralPrefix(arg, "--files-from=")) {
@@ -1065,37 +1068,60 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
format) != cm::cend(knownFormats);
if (!isKnown) {
- cmSystemTools::Error("Unknown -E tar --format= argument: ",
- format.c_str());
+ cmSystemTools::Error("Unknown -E tar --format= argument: " +
+ format);
return 1;
}
} else {
- cmSystemTools::Error("Unknown option to -E tar: ", arg.c_str());
+ cmSystemTools::Error("Unknown option to -E tar: " + arg);
return 1;
}
} else {
files.push_back(arg);
}
}
- cmSystemTools::cmTarCompression compress =
- cmSystemTools::TarCompressNone;
+ cmSystemTools::cmTarAction action = cmSystemTools::TarActionNone;
bool verbose = false;
- int nCompress = 0;
- if (flags.find_first_of('j') != std::string::npos) {
- compress = cmSystemTools::TarCompressBZip2;
- ++nCompress;
- }
- if (flags.find_first_of('J') != std::string::npos) {
- compress = cmSystemTools::TarCompressXZ;
- ++nCompress;
- }
- if (flags.find_first_of('z') != std::string::npos) {
- compress = cmSystemTools::TarCompressGZip;
- ++nCompress;
+
+ for (auto flag : flags) {
+ switch (flag) {
+ case '-':
+ case 'f': {
+ // Keep for backward compatibility. Ignored
+ } break;
+ case 'j': {
+ compress = cmSystemTools::TarCompressBZip2;
+ ++nCompress;
+ } break;
+ case 'J': {
+ compress = cmSystemTools::TarCompressXZ;
+ ++nCompress;
+ } break;
+ case 'z': {
+ compress = cmSystemTools::TarCompressGZip;
+ ++nCompress;
+ } break;
+ case 'v': {
+ verbose = true;
+ } break;
+ case 't': {
+ action = cmSystemTools::TarActionList;
+ } break;
+ case 'c': {
+ action = cmSystemTools::TarActionCreate;
+ } break;
+ case 'x': {
+ action = cmSystemTools::TarActionExtract;
+ } break;
+ default: {
+ cmSystemTools::Message(
+ std::string("tar: Unknown argument: ") + flag, "Warning");
+ }
+ }
}
if ((format == "7zip" || format == "zip") && nCompress > 0) {
- cmSystemTools::Error("Can not use compression flags with format: ",
- format.c_str());
+ cmSystemTools::Error("Can not use compression flags with format: " +
+ format);
return 1;
}
if (nCompress > 1) {
@@ -1103,24 +1129,24 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
"at most one flag of z, j, or J may be used");
return 1;
}
- if (flags.find_first_of('v') != std::string::npos) {
- verbose = true;
- }
-
- if (flags.find_first_of('t') != std::string::npos) {
- if (!cmSystemTools::ListTar(outFile.c_str(), verbose)) {
- cmSystemTools::Error("Problem listing tar: ", outFile.c_str());
+ if (action == cmSystemTools::TarActionList) {
+ if (!cmSystemTools::ListTar(outFile, files, verbose)) {
+ cmSystemTools::Error("Problem listing tar: " + outFile);
return 1;
}
- } else if (flags.find_first_of('c') != std::string::npos) {
- if (!cmSystemTools::CreateTar(outFile.c_str(), files, compress,
- verbose, mtime, format)) {
- cmSystemTools::Error("Problem creating tar: ", outFile.c_str());
+ } else if (action == cmSystemTools::TarActionCreate) {
+ if (files.empty()) {
+ cmSystemTools::Message("tar: No files or directories specified",
+ "Warning");
+ }
+ if (!cmSystemTools::CreateTar(outFile, files, compress, verbose, mtime,
+ format)) {
+ cmSystemTools::Error("Problem creating tar: " + outFile);
return 1;
}
- } else if (flags.find_first_of('x') != std::string::npos) {
- if (!cmSystemTools::ExtractTar(outFile.c_str(), verbose)) {
- cmSystemTools::Error("Problem extracting tar: ", outFile.c_str());
+ } else if (action == cmSystemTools::TarActionExtract) {
+ if (!cmSystemTools::ExtractTar(outFile, files, verbose)) {
+ cmSystemTools::Error("Problem extracting tar: " + outFile);
return 1;
}
#ifdef WIN32
@@ -1139,6 +1165,10 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
cmSystemTools::Delay(delay);
}
#endif
+ } else {
+ cmSystemTools::Error("tar: No action specified. Please choose: 't' "
+ "(list), 'c' (create) or 'x' (extract)");
+ return 1;
}
return 0;
}
@@ -1149,17 +1179,15 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
bool isDebug = false;
std::string pipe;
- for (size_t i = 2; i < args.size(); ++i) {
- const std::string& a = args[i];
-
- if (a == "--experimental") {
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (arg == "--experimental") {
supportExperimental = true;
- } else if (a == "--debug") {
+ } else if (arg == "--debug") {
pipe.clear();
isDebug = true;
- } else if (a.substr(0, pipePrefix.size()) == pipePrefix) {
+ } else if (arg.substr(0, pipePrefix.size()) == pipePrefix) {
isDebug = false;
- pipe = a.substr(pipePrefix.size());
+ pipe = arg.substr(pipePrefix.size());
if (pipe.empty()) {
cmSystemTools::Error("No pipe given after --pipe=");
return 2;
@@ -1231,15 +1259,15 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
return 1;
}
-int cmcmd::HashSumFile(std::vector<std::string>& args, cmCryptoHash::Algo algo)
+int cmcmd::HashSumFile(std::vector<std::string> const& args,
+ cmCryptoHash::Algo algo)
{
if (args.size() < 3) {
return -1;
}
int retval = 0;
- for (std::string::size_type cc = 2; cc < args.size(); cc++) {
- const char* filename = args[cc].c_str();
+ for (auto const& filename : cmMakeRange(args).advance(2)) {
// Cannot compute sum of a directory
if (cmSystemTools::FileIsDirectory(filename)) {
std::cerr << "Error: " << filename << " is a directory" << std::endl;
@@ -1258,7 +1286,7 @@ int cmcmd::HashSumFile(std::vector<std::string>& args, cmCryptoHash::Algo algo)
return retval;
}
-int cmcmd::SymlinkLibrary(std::vector<std::string>& args)
+int cmcmd::SymlinkLibrary(std::vector<std::string> const& args)
{
int result = 0;
std::string realName = args[2];
@@ -1282,7 +1310,7 @@ int cmcmd::SymlinkLibrary(std::vector<std::string>& args)
return result;
}
-int cmcmd::SymlinkExecutable(std::vector<std::string>& args)
+int cmcmd::SymlinkExecutable(std::vector<std::string> const& args)
{
int result = 0;
std::string const& realName = args[2];
@@ -1356,7 +1384,7 @@ static void cmcmdProgressReport(std::string const& dir, std::string const& num)
}
}
-int cmcmd::ExecuteEchoColor(std::vector<std::string>& args)
+int cmcmd::ExecuteEchoColor(std::vector<std::string> const& args)
{
// The arguments are
// args[0] == <cmake-executable>
@@ -1366,55 +1394,54 @@ int cmcmd::ExecuteEchoColor(std::vector<std::string>& args)
int color = cmsysTerminal_Color_Normal;
bool newline = true;
std::string progressDir;
- for (unsigned int i = 2; i < args.size(); ++i) {
- if (args[i].find("--switch=") == 0) {
+ for (auto const& arg : cmMakeRange(args).advance(2)) {
+ if (arg.find("--switch=") == 0) {
// Enable or disable color based on the switch value.
- std::string value = args[i].substr(9);
+ std::string value = arg.substr(9);
if (!value.empty()) {
enabled = cmSystemTools::IsOn(value);
}
- } else if (cmHasLiteralPrefix(args[i], "--progress-dir=")) {
- progressDir = args[i].substr(15);
- } else if (cmHasLiteralPrefix(args[i], "--progress-num=")) {
+ } else if (cmHasLiteralPrefix(arg, "--progress-dir=")) {
+ progressDir = arg.substr(15);
+ } else if (cmHasLiteralPrefix(arg, "--progress-num=")) {
if (!progressDir.empty()) {
- std::string const& progressNum = args[i].substr(15);
+ std::string const& progressNum = arg.substr(15);
cmcmdProgressReport(progressDir, progressNum);
}
- } else if (args[i] == "--normal") {
+ } else if (arg == "--normal") {
color = cmsysTerminal_Color_Normal;
- } else if (args[i] == "--black") {
+ } else if (arg == "--black") {
color = cmsysTerminal_Color_ForegroundBlack;
- } else if (args[i] == "--red") {
+ } else if (arg == "--red") {
color = cmsysTerminal_Color_ForegroundRed;
- } else if (args[i] == "--green") {
+ } else if (arg == "--green") {
color = cmsysTerminal_Color_ForegroundGreen;
- } else if (args[i] == "--yellow") {
+ } else if (arg == "--yellow") {
color = cmsysTerminal_Color_ForegroundYellow;
- } else if (args[i] == "--blue") {
+ } else if (arg == "--blue") {
color = cmsysTerminal_Color_ForegroundBlue;
- } else if (args[i] == "--magenta") {
+ } else if (arg == "--magenta") {
color = cmsysTerminal_Color_ForegroundMagenta;
- } else if (args[i] == "--cyan") {
+ } else if (arg == "--cyan") {
color = cmsysTerminal_Color_ForegroundCyan;
- } else if (args[i] == "--white") {
+ } else if (arg == "--white") {
color = cmsysTerminal_Color_ForegroundWhite;
- } else if (args[i] == "--bold") {
+ } else if (arg == "--bold") {
color |= cmsysTerminal_Color_ForegroundBold;
- } else if (args[i] == "--no-newline") {
+ } else if (arg == "--no-newline") {
newline = false;
- } else if (args[i] == "--newline") {
+ } else if (arg == "--newline") {
newline = true;
} else {
// Color is enabled. Print with the current color.
- cmSystemTools::MakefileColorEcho(color, args[i].c_str(), newline,
- enabled);
+ cmSystemTools::MakefileColorEcho(color, arg.c_str(), newline, enabled);
}
}
return 0;
}
-int cmcmd::ExecuteLinkScript(std::vector<std::string>& args)
+int cmcmd::ExecuteLinkScript(std::vector<std::string> const& args)
{
// The arguments are
// args[0] == <cmake-executable>
@@ -1627,9 +1654,9 @@ std::ostream& operator<<(std::ostream& stream,
return stream;
}
-static bool RunCommand(const char* comment, std::vector<std::string>& command,
- bool verbose, NumberFormat exitFormat,
- int* retCodeOut = nullptr,
+static bool RunCommand(const char* comment,
+ std::vector<std::string> const& command, bool verbose,
+ NumberFormat exitFormat, int* retCodeOut = nullptr,
bool (*retCodeOkay)(int) = nullptr)
{
if (verbose) {
@@ -1830,7 +1857,8 @@ int cmVSLink::LinkIncremental()
// Compile the resource file.
std::vector<std::string> rcCommand;
rcCommand.push_back(this->RcPath.empty() ? "rc" : this->RcPath);
- rcCommand.push_back("/fo" + this->ManifestFileRes);
+ rcCommand.emplace_back("/fo");
+ rcCommand.push_back(this->ManifestFileRes);
rcCommand.push_back(this->ManifestFileRC);
if (!RunCommand("RC Pass 1", rcCommand, this->Verbose, FORMAT_DECIMAL)) {
return -1;
@@ -1894,8 +1922,7 @@ int cmVSLink::RunMT(std::string const& out, bool notify)
if (this->LinkGeneratesManifest) {
mtCommand.push_back(this->LinkerManifestFile);
}
- mtCommand.insert(mtCommand.end(), this->UserManifests.begin(),
- this->UserManifests.end());
+ cmAppend(mtCommand, this->UserManifests);
mtCommand.push_back(out);
if (notify) {
// Add an undocumented option that enables a special return
diff --git a/Source/cmcmd.h b/Source/cmcmd.h
index d1e03d01f..69a7ecbb1 100644
--- a/Source/cmcmd.h
+++ b/Source/cmcmd.h
@@ -16,18 +16,18 @@ public:
* Execute commands during the build process. Supports options such
* as echo, remove file etc.
*/
- static int ExecuteCMakeCommand(std::vector<std::string>&);
+ static int ExecuteCMakeCommand(std::vector<std::string> const&);
protected:
- static int HandleCoCompileCommands(std::vector<std::string>& args);
- static int HashSumFile(std::vector<std::string>& args,
+ static int HandleCoCompileCommands(std::vector<std::string> const& args);
+ static int HashSumFile(std::vector<std::string> const& args,
cmCryptoHash::Algo algo);
- static int SymlinkLibrary(std::vector<std::string>& args);
- static int SymlinkExecutable(std::vector<std::string>& args);
+ static int SymlinkLibrary(std::vector<std::string> const& args);
+ static int SymlinkExecutable(std::vector<std::string> const& args);
static bool SymlinkInternal(std::string const& file,
std::string const& link);
- static int ExecuteEchoColor(std::vector<std::string>& args);
- static int ExecuteLinkScript(std::vector<std::string>& args);
+ static int ExecuteEchoColor(std::vector<std::string> const& args);
+ static int ExecuteLinkScript(std::vector<std::string> const& args);
static int WindowsCEEnvironment(const char* version,
const std::string& name);
static int VisualStudioLink(std::vector<std::string> const& args, int type);
diff --git a/Source/ctest.cxx b/Source/ctest.cxx
index 4a2531a4e..3b3630fc9 100644
--- a/Source/ctest.cxx
+++ b/Source/ctest.cxx
@@ -143,6 +143,7 @@ static const char* cmDocumentationOptions[][2] = {
// this is a test driver program for cmCTest.
int main(int argc, char const* const* argv)
{
+ cmSystemTools::EnsureStdPipes();
#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
// Replace streambuf so we can output Unicode to console
cmsys::ConsoleBuf::Manager consoleOut(std::cout);
@@ -191,8 +192,7 @@ int main(int argc, char const* const* argv)
doc.addCTestStandardDocSections();
if (doc.CheckOptions(argc, argv)) {
// Construct and print requested documentation.
- cmCTestScriptHandler* ch =
- static_cast<cmCTestScriptHandler*>(inst.GetHandler("script"));
+ cmCTestScriptHandler* ch = inst.GetScriptHandler();
ch->CreateCMake();
doc.SetShowGenerators(false);
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
index e7da99462..79e813eef 100644
--- a/Source/kwsys/CMakeLists.txt
+++ b/Source/kwsys/CMakeLists.txt
@@ -120,7 +120,14 @@ SET_PROPERTY(DIRECTORY
if(KWSYS_CXX_STANDARD)
set(CMAKE_CXX_STANDARD "${KWSYS_CXX_STANDARD}")
elseif(NOT DEFINED CMAKE_CXX_STANDARD AND NOT DEFINED KWSYS_CXX_STANDARD)
- set(CMAKE_CXX_STANDARD 11)
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
+ AND "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC"
+ AND "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU"
+ )
+ set(CMAKE_CXX_STANDARD 14)
+ else()
+ set(CMAKE_CXX_STANDARD 11)
+ endif()
endif()
# Select library components.
@@ -172,6 +179,9 @@ ENDIF()
IF(KWSYS_USE_Directory)
SET(KWSYS_USE_Encoding 1)
ENDIF()
+IF(KWSYS_USE_DynamicLoader)
+ SET(KWSYS_USE_Encoding 1)
+ENDIF()
IF(KWSYS_USE_FStream)
SET(KWSYS_USE_Encoding 1)
ENDIF()
@@ -179,13 +189,6 @@ IF(KWSYS_USE_ConsoleBuf)
SET(KWSYS_USE_Encoding 1)
ENDIF()
-# Setup the large file support default.
-IF(KWSYS_LFS_DISABLE)
- SET(KWSYS_LFS_REQUESTED 0)
-ELSE()
- SET(KWSYS_LFS_REQUESTED 1)
-ENDIF()
-
# Specify default 8 bit encoding for Windows
IF(NOT KWSYS_ENCODING_DEFAULT_CODEPAGE)
SET(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_ACP)
@@ -353,30 +356,6 @@ IF(KWSYS_STANDALONE)
ENDIF()
#-----------------------------------------------------------------------------
-# Configure Large File Support.
-KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CSTDIO
- "Checking whether header cstdio is available" DIRECT)
-SET(KWSYS_LFS_AVAILABLE 0)
-IF(KWSYS_LFS_REQUESTED)
- # Large File Support is requested.
- SET(KWSYS_LFS_REQUESTED 1)
-
- # Check for large file support.
- SET(KWSYS_PLATFORM_CXX_TEST_DEFINES
- -DKWSYS_CXX_HAS_CSTDIO=${KWSYS_CXX_HAS_CSTDIO})
- KWSYS_PLATFORM_CXX_TEST_RUN(KWSYS_LFS_WORKS
- "Checking for Large File Support" DIRECT)
- SET(KWSYS_PLATFORM_CXX_TEST_DEFINES)
-
- IF(KWSYS_LFS_WORKS)
- SET(KWSYS_LFS_AVAILABLE 1)
- ENDIF()
-ELSE()
- # Large File Support is not requested.
- SET(KWSYS_LFS_REQUESTED 0)
-ENDIF()
-
-#-----------------------------------------------------------------------------
# Configure the standard library header wrappers based on compiler's
# capabilities and parent project's request. Enforce 0/1 as only
# possible values for configuration into Configure.hxx.
@@ -493,6 +472,14 @@ IF(KWSYS_USE_DynamicLoader)
ENDIF()
IF(KWSYS_USE_SystemTools)
+ if (NOT DEFINED KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP)
+ set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1)
+ endif ()
+ if (KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP)
+ set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1)
+ else ()
+ set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 0)
+ endif ()
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_SETENV
"Checking whether CXX compiler has setenv" DIRECT)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UNSETENV
@@ -575,9 +562,6 @@ IF(KWSYS_USE_SystemInformation)
COMPILE_DEFINITIONS KWSYS_SYS_HAS_MACHINE_CPU_H=1)
ENDIF()
ENDIF()
- IF(KWSYS_LFS_AVAILABLE AND NOT KWSYS_LFS_DISABLE)
- SET(KWSYS_PLATFORM_CXX_TEST_DEFINES -DKWSYS_HAS_LFS=1)
- ENDIF()
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_RLIMIT64
"Checking whether CXX compiler has rlimit64" DIRECT)
SET(KWSYS_PLATFORM_CXX_TEST_DEFINES)
@@ -917,6 +901,11 @@ IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS)
IF(KWSYS_USE_SystemInformation)
IF(WIN32)
TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} ws2_32)
+ # link in dbghelp.dll for symbol lookup if MSVC 1800 or later
+ # Note that the dbghelp runtime is part of MS Windows OS
+ IF(MSVC_VERSION AND NOT MSVC_VERSION VERSION_LESS 1800)
+ TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} dbghelp)
+ ENDIF()
IF(KWSYS_SYS_HAS_PSAPI)
TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY}
Psapi)
@@ -1023,7 +1012,8 @@ ENDIF()
ADD_DEFINITIONS("-DKWSYS_NAMESPACE=${KWSYS_NAMESPACE}")
# Disable deprecation warnings for standard C functions.
-IF(MSVC OR (WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "Intel"))
+IF(MSVC OR (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "Intel" OR
+ (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC"))))
ADD_DEFINITIONS(
-D_CRT_NONSTDC_NO_DEPRECATE
-D_CRT_SECURE_NO_DEPRECATE
@@ -1130,6 +1120,20 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
ADD_LIBRARY(${KWSYS_NAMESPACE}TestDynload MODULE testDynload.c)
SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestDynload PROPERTY LABELS ${KWSYS_LABELS_LIB})
ADD_DEPENDENCIES(${KWSYS_NAMESPACE}TestDynload ${KWSYS_TARGET_INTERFACE})
+
+ if (WIN32)
+ # Windows tests supported flags.
+ add_library(${KWSYS_NAMESPACE}TestDynloadImpl SHARED testDynloadImpl.c)
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY LABELS ${KWSYS_LABELS_LIB})
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY DEFINE_SYMBOL BUILDING_TestDynloadImpl)
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir")
+ add_dependencies(${KWSYS_NAMESPACE}TestDynloadImpl ${KWSYS_TARGET_INTERFACE})
+ add_library(${KWSYS_NAMESPACE}TestDynloadUse MODULE testDynloadUse.c)
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LABELS ${KWSYS_LABELS_LIB})
+ set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir")
+ add_dependencies(${KWSYS_NAMESPACE}TestDynloadUse ${KWSYS_TARGET_INTERFACE})
+ target_link_libraries(${KWSYS_NAMESPACE}TestDynloadUse PRIVATE ${KWSYS_NAMESPACE}TestDynloadImpl)
+ endif ()
ENDIF()
CREATE_TEST_SOURCELIST(
KWSYS_CXX_TEST_SRCS ${KWSYS_NAMESPACE}TestsCxx.cxx
diff --git a/Source/kwsys/CommandLineArguments.hxx.in b/Source/kwsys/CommandLineArguments.hxx.in
index 31115e51f..7db901556 100644
--- a/Source/kwsys/CommandLineArguments.hxx.in
+++ b/Source/kwsys/CommandLineArguments.hxx.in
@@ -62,6 +62,9 @@ public:
CommandLineArguments();
~CommandLineArguments();
+ CommandLineArguments(const CommandLineArguments&) = delete;
+ CommandLineArguments& operator=(const CommandLineArguments&) = delete;
+
/**
* Various argument types.
*/
diff --git a/Source/kwsys/Configure.h.in b/Source/kwsys/Configure.h.in
index bec1abca4..5323c57be 100644
--- a/Source/kwsys/Configure.h.in
+++ b/Source/kwsys/Configure.h.in
@@ -28,43 +28,6 @@
/* Whether kwsys namespace is "kwsys". */
#define @KWSYS_NAMESPACE@_NAME_IS_KWSYS @KWSYS_NAME_IS_KWSYS@
-/* Whether Large File Support is requested. */
-#define @KWSYS_NAMESPACE@_LFS_REQUESTED @KWSYS_LFS_REQUESTED@
-
-/* Whether Large File Support is available. */
-#if @KWSYS_NAMESPACE@_LFS_REQUESTED
-# define @KWSYS_NAMESPACE@_LFS_AVAILABLE @KWSYS_LFS_AVAILABLE@
-#endif
-
-/* Setup Large File Support if requested. */
-#if @KWSYS_NAMESPACE@_LFS_REQUESTED
-/* Since LFS is requested this header must be included before system
- headers whether or not LFS is available. */
-# if 0 && (defined(_SYS_TYPES_H) || defined(_SYS_TYPES_INCLUDED))
-# error "@KWSYS_NAMESPACE@/Configure.h must be included before sys/types.h"
-# endif
-/* Enable the large file API if it is available. */
-# if @KWSYS_NAMESPACE@_LFS_AVAILABLE && \
- !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINES)
-# if !defined(_LARGEFILE_SOURCE) && \
- !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGEFILE_SOURCE)
-# define _LARGEFILE_SOURCE
-# endif
-# if !defined(_LARGEFILE64_SOURCE) && \
- !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGEFILE64_SOURCE)
-# define _LARGEFILE64_SOURCE
-# endif
-# if !defined(_LARGE_FILES) && \
- !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_LARGE_FILES)
-# define _LARGE_FILES
-# endif
-# if !defined(_FILE_OFFSET_BITS) && \
- !defined(@KWSYS_NAMESPACE@_LFS_NO_DEFINE_FILE_OFFSET_BITS)
-# define _FILE_OFFSET_BITS 64
-# endif
-# endif
-#endif
-
/* Setup the export macro. */
#if @KWSYS_BUILD_SHARED@
# if defined(_WIN32) || defined(__CYGWIN__)
diff --git a/Source/kwsys/Configure.hxx.in b/Source/kwsys/Configure.hxx.in
index d1e7464ff..92ffea3c9 100644
--- a/Source/kwsys/Configure.hxx.in
+++ b/Source/kwsys/Configure.hxx.in
@@ -11,6 +11,9 @@
/* Whether <ext/stdio_filebuf.h> is available. */
#define @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H \
@KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@
+/* Whether the translation map is available or not. */
+#define @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP \
+ @KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP@
#if defined(__SUNPRO_CC) && __SUNPRO_CC > 0x5130 && defined(__has_attribute)
# define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_attribute(x)
@@ -56,6 +59,8 @@
@KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H
# define KWSYS_FALLTHROUGH @KWSYS_NAMESPACE@_FALLTHROUGH
# define KWSYS_NULLPTR @KWSYS_NAMESPACE@_NULLPTR
+# define KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP \
+ @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP
#endif
#endif
diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx
index 31b1c15d0..59530a43f 100644
--- a/Source/kwsys/Directory.cxx
+++ b/Source/kwsys/Directory.cxx
@@ -102,7 +102,7 @@ bool Directory::Load(const std::string& name)
# endif
char* buf;
size_t n = name.size();
- if (*name.rbegin() == '/' || *name.rbegin() == '\\') {
+ if (name.back() == '/' || name.back() == '\\') {
buf = new char[n + 1 + 1];
sprintf(buf, "%s*", name.c_str());
} else {
@@ -144,7 +144,7 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name)
# endif
char* buf;
size_t n = name.size();
- if (*name.rbegin() == '/') {
+ if (name.back() == '/') {
buf = new char[n + 1 + 1];
sprintf(buf, "%s*", name.c_str());
} else {
diff --git a/Source/kwsys/DynamicLoader.cxx b/Source/kwsys/DynamicLoader.cxx
index a85690f7c..b93a215cc 100644
--- a/Source/kwsys/DynamicLoader.cxx
+++ b/Source/kwsys/DynamicLoader.cxx
@@ -1,9 +1,14 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
+#if defined(_WIN32)
+# define NOMINMAX // hide min,max to not conflict with <limits>
+#endif
+
#include "kwsysPrivate.h"
#include KWSYS_HEADER(DynamicLoader.hxx)
#include KWSYS_HEADER(Configure.hxx)
+#include KWSYS_HEADER(Encoding.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
@@ -25,6 +30,28 @@
// Each part of the ifdef contains a complete implementation for
// the static methods of DynamicLoader.
+#define CHECK_OPEN_FLAGS(var, supported, ret) \
+ do { \
+ /* Check for unknown flags. */ \
+ if ((var & AllOpenFlags) != var) { \
+ return ret; \
+ } \
+ \
+ /* Check for unsupported flags. */ \
+ if ((var & (supported)) != var) { \
+ return ret; \
+ } \
+ } while (0)
+
+namespace KWSYS_NAMESPACE {
+
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+ const std::string& libname)
+{
+ return DynamicLoader::OpenLibrary(libname, 0);
+}
+}
+
#if !KWSYS_SUPPORTS_SHARED_LIBS
// Implementation for environments without dynamic libs
# include <string.h> // for strerror()
@@ -32,7 +59,7 @@
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
- const std::string& libname)
+ const std::string& libname, int flags)
{
return 0;
}
@@ -67,8 +94,10 @@ const char* DynamicLoader::LastError()
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
- const std::string& libname)
+ const std::string& libname, int flags)
{
+ CHECK_OPEN_FLAGS(flags, 0, 0);
+
return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L);
}
@@ -130,8 +159,10 @@ const char* DynamicLoader::LastError()
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
- const std::string& libname)
+ const std::string& libname, int flags)
{
+ CHECK_OPEN_FLAGS(flags, 0, 0);
+
NSObjectFileImageReturnCode rc;
NSObjectFileImage image = 0;
@@ -185,19 +216,22 @@ const char* DynamicLoader::LastError()
// Implementation for Windows win32 code but not cygwin
# include <windows.h>
+# include <stdio.h>
+
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
- const std::string& libname)
+ const std::string& libname, int flags)
{
- DynamicLoader::LibraryHandle lh;
- int length = MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, NULL, 0);
- wchar_t* wchars = new wchar_t[length + 1];
- wchars[0] = '\0';
- MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, wchars, length);
- lh = LoadLibraryW(wchars);
- delete[] wchars;
- return lh;
+ CHECK_OPEN_FLAGS(flags, SearchBesideLibrary, NULL);
+
+ DWORD llFlags = 0;
+ if (flags & SearchBesideLibrary) {
+ llFlags |= LOAD_WITH_ALTERED_SEARCH_PATH;
+ }
+
+ return LoadLibraryExW(Encoding::ToWindowsExtendedPath(libname).c_str(), NULL,
+ llFlags);
}
int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
@@ -247,24 +281,38 @@ DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
# endif
}
+# define DYNLOAD_ERROR_BUFFER_SIZE 1024
+
const char* DynamicLoader::LastError()
{
- LPVOID lpMsgBuf = NULL;
-
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (LPTSTR)&lpMsgBuf, 0, NULL);
+ wchar_t lpMsgBuf[DYNLOAD_ERROR_BUFFER_SIZE + 1];
+
+ DWORD error = GetLastError();
+ DWORD length = FormatMessageW(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ lpMsgBuf, DYNLOAD_ERROR_BUFFER_SIZE, NULL);
+
+ static char str[DYNLOAD_ERROR_BUFFER_SIZE + 1];
+
+ if (length < 1) {
+ /* FormatMessage failed. Use a default message. */
+ _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE,
+ "DynamicLoader encountered error 0x%X. "
+ "FormatMessage failed with error 0x%X",
+ error, GetLastError());
+ return str;
+ }
- if (!lpMsgBuf) {
- return NULL;
+ if (!WideCharToMultiByte(CP_UTF8, 0, lpMsgBuf, -1, str,
+ DYNLOAD_ERROR_BUFFER_SIZE, NULL, NULL)) {
+ /* WideCharToMultiByte failed. Use a default message. */
+ _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE,
+ "DynamicLoader encountered error 0x%X. "
+ "WideCharToMultiByte failed with error 0x%X",
+ error, GetLastError());
}
- static char* str = 0;
- delete[] str;
- str = strcpy(new char[strlen((char*)lpMsgBuf) + 1], (char*)lpMsgBuf);
- // Free the buffer.
- LocalFree(lpMsgBuf);
return str;
}
@@ -282,8 +330,10 @@ namespace KWSYS_NAMESPACE {
static image_id last_dynamic_err = B_OK;
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
- const std::string& libname)
+ const std::string& libname, int flags)
{
+ CHECK_OPEN_FLAGS(flags, 0, 0);
+
// image_id's are integers, errors are negative. Add one just in case we
// get a valid image_id of zero (is that even possible?).
image_id rc = load_add_on(libname.c_str());
@@ -360,8 +410,10 @@ const char* DynamicLoader::LastError()
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
- const std::string& libname)
+ const std::string& libname, int flags)
{
+ CHECK_OPEN_FLAGS(flags, 0, NULL);
+
char* name = (char*)calloc(1, libname.size() + 1);
dld_init(program_invocation_name);
strncpy(name, libname.c_str(), libname.size());
@@ -404,8 +456,10 @@ const char* DynamicLoader::LastError()
namespace KWSYS_NAMESPACE {
DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
- const std::string& libname)
+ const std::string& libname, int flags)
{
+ CHECK_OPEN_FLAGS(flags, 0, NULL);
+
return dlopen(libname.c_str(), RTLD_LAZY);
}
diff --git a/Source/kwsys/DynamicLoader.hxx.in b/Source/kwsys/DynamicLoader.hxx.in
index 08f2790af..539c74259 100644
--- a/Source/kwsys/DynamicLoader.hxx.in
+++ b/Source/kwsys/DynamicLoader.hxx.in
@@ -66,10 +66,23 @@ public:
// Return type from DynamicLoader::GetSymbolAddress.
typedef void (*SymbolPointer)();
+ enum OpenFlags
+ {
+ // Search for dependent libraries beside the library being loaded.
+ //
+ // This is currently only supported on Windows.
+ SearchBesideLibrary = 0x00000001,
+
+ AllOpenFlags = SearchBesideLibrary
+ };
+
/** Load a dynamic library into the current process.
* The returned LibraryHandle can be used to access the symbols in the
- * library. */
+ * library. The optional second argument is a set of flags to use when
+ * opening the library. If unrecognized or unsupported flags are specified,
+ * the library is not opened. */
static LibraryHandle OpenLibrary(const std::string&);
+ static LibraryHandle OpenLibrary(const std::string&, int);
/** Attempt to detach a dynamic library from the
* process. A value of true is returned if it is successful. */
diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
index 6952d24ae..829c1389f 100644
--- a/Source/kwsys/Glob.cxx
+++ b/Source/kwsys/Glob.cxx
@@ -263,7 +263,7 @@ bool Glob::RecurseDirectory(std::string::size_type start,
}
} else {
if (!this->Internals->Expressions.empty() &&
- this->Internals->Expressions.rbegin()->find(fname)) {
+ this->Internals->Expressions.back().find(fname)) {
this->AddFile(this->Internals->Files, realname);
}
}
diff --git a/Source/kwsys/Glob.hxx.in b/Source/kwsys/Glob.hxx.in
index bd4a17616..4c3bde167 100644
--- a/Source/kwsys/Glob.hxx.in
+++ b/Source/kwsys/Glob.hxx.in
@@ -41,17 +41,9 @@ public:
, content(c)
{
}
- Message(const Message& msg)
- : type(msg.type)
- , content(msg.content)
- {
- }
- Message& operator=(Message const& msg)
- {
- this->type = msg.type;
- this->content = msg.content;
- return *this;
- }
+ ~Message() = default;
+ Message(const Message& msg) = default;
+ Message& operator=(Message const& msg) = default;
};
typedef std::vector<Message> GlobMessages;
diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
index 2a2e73761..68c52185e 100644
--- a/Source/kwsys/ProcessWin32.c
+++ b/Source/kwsys/ProcessWin32.c
@@ -117,7 +117,6 @@ static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1,
kwsysProcessTime in2);
static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1,
kwsysProcessTime in2);
-static void kwsysProcessSetExitException(kwsysProcess* cp, int code);
static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code,
int idx);
static void kwsysProcessKillTree(int pid);
@@ -358,13 +357,20 @@ kwsysProcess* kwsysProcess_New(void)
# 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
GetVersionEx(&osv);
#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-# pragma warning(pop)
+# ifdef __clang__
+# pragma clang diagnostic pop
+# else
+# pragma warning(pop)
+# endif
#endif
if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
/* Win9x no longer supported. */
@@ -2269,13 +2275,20 @@ static kwsysProcess_List* kwsysProcess_List_New(void)
# 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
GetVersionEx(&osv);
#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-# pragma warning(pop)
+# ifdef __clang__
+# pragma clang diagnostic pop
+# else
+# pragma warning(pop)
+# endif
#endif
self->NT4 =
(osv.dwPlatformId == VER_PLATFORM_WIN32_NT && osv.dwMajorVersion < 5) ? 1
@@ -2659,8 +2672,8 @@ static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessid,
newSize = kwsysProcesses.Size ? kwsysProcesses.Size * 2 : 4;
/* Try allocating the new block of memory. */
- if (newArray = (kwsysProcessInstance*)malloc(
- newSize * sizeof(kwsysProcessInstance))) {
+ if ((newArray = (kwsysProcessInstance*)malloc(
+ newSize * sizeof(kwsysProcessInstance)))) {
/* Copy the old process handles to the new memory. */
if (kwsysProcesses.Count > 0) {
memcpy(newArray, kwsysProcesses.Processes,
diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx
index f323efc4b..7dc6cf4b0 100644
--- a/Source/kwsys/SystemInformation.cxx
+++ b/Source/kwsys/SystemInformation.cxx
@@ -2,6 +2,9 @@
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#if defined(_WIN32)
# define NOMINMAX // use our min,max
+# if !defined(_WIN32_WINNT) && defined(_MSC_VER) && _MSC_VER >= 1800
+# define _WIN32_WINNT 0x0600 // vista
+# endif
# if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300)
# define _WIN32_WINNT 0x0501
# endif
@@ -444,6 +447,7 @@ public:
IBM,
Motorola,
HP,
+ Hygon,
UnknownManufacturer
};
@@ -1766,6 +1770,8 @@ const char* SystemInformationImplementation::GetVendorID()
return "Motorola";
case HP:
return "Hewlett-Packard";
+ case Hygon:
+ return "Chengdu Haiguang IC Design Co., Ltd.";
case UnknownManufacturer:
default:
return "Unknown Manufacturer";
@@ -2117,6 +2123,8 @@ void SystemInformationImplementation::FindManufacturer(
this->ChipManufacturer = AMD; // Advanced Micro Devices
else if (this->ChipID.Vendor == "AMD ISBETTER")
this->ChipManufacturer = AMD; // Advanced Micro Devices (1994)
+ else if (this->ChipID.Vendor == "HygonGenuine")
+ this->ChipManufacturer = Hygon; // Chengdu Haiguang IC Design Co., Ltd.
else if (this->ChipID.Vendor == "CyrixInstead")
this->ChipManufacturer = Cyrix; // Cyrix Corp., VIA Inc.
else if (this->ChipID.Vendor == "NexGenDriven")
@@ -2751,7 +2759,7 @@ bool SystemInformationImplementation::RetrieveExtendedCPUFeatures()
0); // MP Capable -- > Bit 19.
// Retrieve AMD specific extended features.
- if (this->ChipManufacturer == AMD) {
+ if (this->ChipManufacturer == AMD || this->ChipManufacturer == Hygon) {
this->Features.ExtendedFeatures.HasMMXPlus =
((localCPUExtendedFeatures[3] & 0x00400000) !=
0); // AMD specific: MMX-SSE --> Bit 22
@@ -3158,6 +3166,10 @@ bool SystemInformationImplementation::RetrieveClassicalCPUIdentity()
}
break;
+ case Hygon:
+ this->ChipID.ProcessorName = "Unknown Hygon family";
+ return false;
+
case Transmeta:
switch (this->ChipID.Family) {
case 5:
@@ -3880,34 +3892,78 @@ SystemInformation::LongLong SystemInformationImplementation::GetProcessId()
}
/**
+ * Used in GetProgramStack(...) below
+ */
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 && defined(_MSC_VER) && \
+ _MSC_VER >= 1800
+# define KWSYS_SYSTEMINFORMATION_HAS_DBGHELP
+# define TRACE_MAX_STACK_FRAMES 1024
+# define TRACE_MAX_FUNCTION_NAME_LENGTH 1024
+# pragma warning(push)
+# pragma warning(disable : 4091) /* 'typedef ': ignored on left of '' */
+# include "dbghelp.h"
+# pragma warning(pop)
+#endif
+
+/**
return current program stack in a string
demangle cxx symbols if possible.
*/
std::string SystemInformationImplementation::GetProgramStack(int firstFrame,
int wholePath)
{
- std::string programStack = ""
-#if !defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
- "WARNING: The stack could not be examined "
- "because backtrace is not supported.\n"
-#elif !defined(KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD)
- "WARNING: The stack trace will not use advanced "
- "capabilities because this is a release build.\n"
+ std::ostringstream oss;
+ std::string programStack = "";
+
+#ifdef KWSYS_SYSTEMINFORMATION_HAS_DBGHELP
+ (void)wholePath;
+
+ void* stack[TRACE_MAX_STACK_FRAMES];
+ HANDLE process = GetCurrentProcess();
+ SymInitialize(process, NULL, TRUE);
+ WORD numberOfFrames =
+ CaptureStackBackTrace(firstFrame, TRACE_MAX_STACK_FRAMES, stack, NULL);
+ SYMBOL_INFO* symbol = static_cast<SYMBOL_INFO*>(
+ malloc(sizeof(SYMBOL_INFO) +
+ (TRACE_MAX_FUNCTION_NAME_LENGTH - 1) * sizeof(TCHAR)));
+ symbol->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH;
+ symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+ DWORD displacement;
+ IMAGEHLP_LINE64 line;
+ line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+ for (int i = 0; i < numberOfFrames; i++) {
+ DWORD64 address = reinterpret_cast<DWORD64>(stack[i]);
+ SymFromAddr(process, address, NULL, symbol);
+ if (SymGetLineFromAddr64(process, address, &displacement, &line)) {
+ oss << " at " << symbol->Name << " in " << line.FileName << " line "
+ << line.LineNumber << std::endl;
+ } else {
+ oss << " at " << symbol->Name << std::endl;
+ }
+ }
+ free(symbol);
+
#else
-# if !defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
- "WARNING: Function names will not be demangled "
- "because "
- "dladdr is not available.\n"
-# endif
-# if !defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
- "WARNING: Function names will not be demangled "
- "because cxxabi is not available.\n"
+ programStack += ""
+# if !defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
+ "WARNING: The stack could not be examined "
+ "because backtrace is not supported.\n"
+# elif !defined(KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD)
+ "WARNING: The stack trace will not use advanced "
+ "capabilities because this is a release build.\n"
+# else
+# if !defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
+ "WARNING: Function names will not be demangled "
+ "because dladdr is not available.\n"
+# endif
+# if !defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
+ "WARNING: Function names will not be demangled "
+ "because cxxabi is not available.\n"
+# endif
# endif
-#endif
;
- std::ostringstream oss;
-#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
+# if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
void* stackSymbols[256];
int nFrames = backtrace(stackSymbols, 256);
for (int i = firstFrame; i < nFrames; ++i) {
@@ -3916,10 +3972,12 @@ std::string SystemInformationImplementation::GetProgramStack(int firstFrame,
symProps.Initialize(stackSymbols[i]);
oss << symProps << std::endl;
}
-#else
+# else
(void)firstFrame;
(void)wholePath;
+# endif
#endif
+
programStack += oss.str();
return programStack;
@@ -4620,7 +4678,7 @@ std::string SystemInformationImplementation::RunProcess(
// Run the application
kwsysProcess* gp = kwsysProcess_New();
- kwsysProcess_SetCommand(gp, &*args.begin());
+ kwsysProcess_SetCommand(gp, args.data());
kwsysProcess_SetOption(gp, kwsysProcess_Option_HideWindow, 1);
kwsysProcess_Execute(gp);
@@ -5147,6 +5205,9 @@ bool SystemInformationImplementation::QueryOSInformation()
# 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
@@ -5159,7 +5220,11 @@ bool SystemInformationImplementation::QueryOSInformation()
}
}
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-# pragma warning(pop)
+# ifdef __clang__
+# pragma clang diagnostic pop
+# else
+# pragma warning(pop)
+# endif
# endif
switch (osvi.dwPlatformId) {
diff --git a/Source/kwsys/SystemInformation.hxx.in b/Source/kwsys/SystemInformation.hxx.in
index 9e1ce6ce2..5e93878fa 100644
--- a/Source/kwsys/SystemInformation.hxx.in
+++ b/Source/kwsys/SystemInformation.hxx.in
@@ -56,6 +56,9 @@ public:
SystemInformation();
~SystemInformation();
+ SystemInformation(const SystemInformation&) = delete;
+ SystemInformation& operator=(const SystemInformation&) = delete;
+
const char* GetVendorString();
const char* GetVendorID();
std::string GetTypeID();
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index d8904fed7..2135913f5 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -28,6 +28,7 @@
#include <iostream>
#include <set>
#include <sstream>
+#include <utility>
#include <vector>
// Work-around CMake dependency scanning limitation. This must
@@ -363,10 +364,6 @@ double SystemTools::GetTime(void)
#endif
}
-class SystemToolsTranslationMap : public std::map<std::string, std::string>
-{
-};
-
/* Type of character storing the environment. */
#if defined(_WIN32)
typedef wchar_t envchar;
@@ -416,6 +413,9 @@ public:
{
}
~Free() { free(const_cast<envchar*>(this->Env)); }
+
+ Free(const Free&) = delete;
+ Free& operator=(const Free&) = delete;
};
const envchar* Release(const envchar* env)
@@ -444,15 +444,141 @@ struct SystemToolsPathCaseCmp
# endif
}
};
+#endif
-class SystemToolsPathCaseMap
- : public std::map<std::string, std::string, SystemToolsPathCaseCmp>
+/**
+ * SystemTools static variables singleton class.
+ */
+class SystemToolsStatic
{
+public:
+ typedef std::map<std::string, std::string> StringMap;
+#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
+ /**
+ * Path translation table from dir to refdir
+ * Each time 'dir' will be found it will be replace by 'refdir'
+ */
+ StringMap TranslationMap;
+#endif
+#ifdef _WIN32
+ static std::string GetCasePathName(std::string const& pathIn);
+ static std::string GetActualCaseForPathCached(std::string const& path);
+ static const char* GetEnvBuffered(const char* key);
+ std::map<std::string, std::string, SystemToolsPathCaseCmp> PathCaseMap;
+ std::map<std::string, std::string> EnvMap;
+#endif
+#ifdef __CYGWIN__
+ StringMap Cyg2Win32Map;
+#endif
+
+ /**
+ * Actual implementation of ReplaceString.
+ */
+ static void ReplaceString(std::string& source, const char* replace,
+ size_t replaceSize, const std::string& with);
+
+ /**
+ * Actual implementation of FileIsFullPath.
+ */
+ static bool FileIsFullPath(const char*, size_t);
+
+ /**
+ * Find a filename (file or directory) in the system PATH, with
+ * optional extra paths.
+ */
+ static std::string FindName(
+ const std::string& name,
+ const std::vector<std::string>& path = std::vector<std::string>(),
+ bool no_system_path = false);
};
-class SystemToolsEnvMap : public std::map<std::string, std::string>
+#ifdef _WIN32
+std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn)
{
-};
+ std::string casePath;
+
+ // First check if the file is relative. We don't fix relative paths since the
+ // real case depends on the root directory and the given path fragment may
+ // have meaning elsewhere in the project.
+ if (!SystemTools::FileIsFullPath(pathIn)) {
+ // This looks unnecessary, but it allows for the return value optimization
+ // since all return paths return the same local variable.
+ casePath = pathIn;
+ return casePath;
+ }
+
+ std::vector<std::string> path_components;
+ SystemTools::SplitPath(pathIn, path_components);
+
+ // Start with root component.
+ std::vector<std::string>::size_type idx = 0;
+ casePath = path_components[idx++];
+ // make sure drive letter is always upper case
+ if (casePath.size() > 1 && casePath[1] == ':') {
+ casePath[0] = toupper(casePath[0]);
+ }
+ const char* sep = "";
+
+ // If network path, fill casePath with server/share so FindFirstFile
+ // will work after that. Maybe someday call other APIs to get
+ // actual case of servers and shares.
+ if (path_components.size() > 2 && path_components[0] == "//") {
+ casePath += path_components[idx++];
+ casePath += "/";
+ casePath += path_components[idx++];
+ sep = "/";
+ }
+
+ // Convert case of all components that exist.
+ bool converting = true;
+ for (; idx < path_components.size(); idx++) {
+ casePath += sep;
+ sep = "/";
+
+ if (converting) {
+ // If path component contains wildcards, we skip matching
+ // because these filenames are not allowed on windows,
+ // and we do not want to match a different file.
+ if (path_components[idx].find('*') != std::string::npos ||
+ path_components[idx].find('?') != std::string::npos) {
+ converting = false;
+ } 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;
+ }
+ }
+ }
+
+ casePath += path_components[idx];
+ }
+ return casePath;
+}
+
+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 = SystemTools::Statics->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;
+ }
+ return casePath;
+}
#endif
// adds the elements of the env variable path to the arg passed in
@@ -473,7 +599,7 @@ void SystemTools::GetPath(std::vector<std::string>& path, const char* env)
}
// A hack to make the below algorithm work.
- if (!pathEnv.empty() && *pathEnv.rbegin() != pathSep) {
+ if (!pathEnv.empty() && pathEnv.back() != pathSep) {
pathEnv += pathSep;
}
std::string::size_type start = 0;
@@ -493,30 +619,37 @@ void SystemTools::GetPath(std::vector<std::string>& path, const char* env)
}
}
-const char* SystemTools::GetEnvImpl(const char* key)
-{
- const char* v = KWSYS_NULLPTR;
#if defined(_WIN32)
+const char* SystemToolsStatic::GetEnvBuffered(const char* key)
+{
std::string env;
if (SystemTools::GetEnv(key, env)) {
- std::string& menv = (*SystemTools::EnvMap)[key];
- menv = env;
- v = menv.c_str();
+ std::string& menv = SystemTools::Statics->EnvMap[key];
+ if (menv != env) {
+ menv = std::move(env);
+ }
+ return menv.c_str();
}
-#else
- v = getenv(key);
-#endif
- return v;
+ return KWSYS_NULLPTR;
}
+#endif
const char* SystemTools::GetEnv(const char* key)
{
- return SystemTools::GetEnvImpl(key);
+#if defined(_WIN32)
+ return SystemToolsStatic::GetEnvBuffered(key);
+#else
+ return getenv(key);
+#endif
}
const char* SystemTools::GetEnv(const std::string& key)
{
- return SystemTools::GetEnvImpl(key.c_str());
+#if defined(_WIN32)
+ return SystemToolsStatic::GetEnvBuffered(key.c_str());
+#else
+ return getenv(key.c_str());
+#endif
}
bool SystemTools::GetEnv(const char* key, std::string& result)
@@ -819,7 +952,8 @@ void SystemTools::ReplaceString(std::string& source,
return;
}
- SystemTools::ReplaceString(source, replace.c_str(), replace.size(), with);
+ SystemToolsStatic::ReplaceString(source, replace.c_str(), replace.size(),
+ with);
}
void SystemTools::ReplaceString(std::string& source, const char* replace,
@@ -830,12 +964,13 @@ void SystemTools::ReplaceString(std::string& source, const char* replace,
return;
}
- SystemTools::ReplaceString(source, replace, strlen(replace),
- with ? with : "");
+ SystemToolsStatic::ReplaceString(source, replace, strlen(replace),
+ with ? with : "");
}
-void SystemTools::ReplaceString(std::string& source, const char* replace,
- size_t replaceSize, const std::string& with)
+void SystemToolsStatic::ReplaceString(std::string& source, const char* replace,
+ size_t replaceSize,
+ const std::string& with)
{
const char* src = source.c_str();
char* searchPos = const_cast<char*>(strstr(src, replace));
@@ -1313,18 +1448,16 @@ int SystemTools::Stat(const std::string& path, SystemTools::Stat_t* buf)
#ifdef __CYGWIN__
bool SystemTools::PathCygwinToWin32(const char* path, char* win32_path)
{
- SystemToolsTranslationMap::iterator i =
- SystemTools::Cyg2Win32Map->find(path);
-
- if (i != SystemTools::Cyg2Win32Map->end()) {
- strncpy(win32_path, i->second.c_str(), MAX_PATH);
+ auto itr = SystemTools::Statics->Cyg2Win32Map.find(path);
+ if (itr != SystemTools::Statics->Cyg2Win32Map.end()) {
+ strncpy(win32_path, itr->second.c_str(), MAX_PATH);
} else {
if (cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, win32_path, MAX_PATH) !=
0) {
win32_path[0] = 0;
}
- SystemToolsTranslationMap::value_type entry(path, win32_path);
- SystemTools::Cyg2Win32Map->insert(entry);
+ SystemTools::Statics->Cyg2Win32Map.insert(
+ SystemToolsStatic::StringMap::value_type(path, win32_path));
}
return win32_path[0] != 0;
}
@@ -1943,7 +2076,7 @@ void SystemTools::ConvertToUnixSlashes(std::string& path)
// a single /
pathCString = path.c_str();
size_t size = path.size();
- if (size > 1 && *path.rbegin() == '/') {
+ if (size > 1 && path.back() == '/') {
// if it is c:/ then do not remove the trailing slash
if (!((size == 3 && pathCString[1] == ':'))) {
path.resize(size - 1);
@@ -2670,9 +2803,9 @@ size_t SystemTools::GetMaximumFilePathLength()
* the system search path. Returns the full path to the file if it is
* found. Otherwise, the empty string is returned.
*/
-std::string SystemTools::FindName(const std::string& name,
- const std::vector<std::string>& userPaths,
- bool no_system_path)
+std::string SystemToolsStatic::FindName(
+ const std::string& name, const std::vector<std::string>& userPaths,
+ bool no_system_path)
{
// Add the system search path to our path first
std::vector<std::string> path;
@@ -2681,27 +2814,15 @@ std::string SystemTools::FindName(const std::string& name,
SystemTools::GetPath(path);
}
// now add the additional paths
- {
- for (std::vector<std::string>::const_iterator i = userPaths.begin();
- i != userPaths.end(); ++i) {
- path.push_back(*i);
- }
- }
- // Add a trailing slash to all paths to aid the search process.
- {
- for (std::vector<std::string>::iterator i = path.begin(); i != path.end();
- ++i) {
- std::string& p = *i;
- if (p.empty() || *p.rbegin() != '/') {
- p += "/";
- }
- }
- }
+ path.reserve(path.size() + userPaths.size());
+ path.insert(path.end(), userPaths.begin(), userPaths.end());
// now look for the file
std::string tryPath;
- for (std::vector<std::string>::const_iterator p = path.begin();
- p != path.end(); ++p) {
- tryPath = *p;
+ for (std::string const& p : path) {
+ tryPath = p;
+ if (tryPath.empty() || tryPath.back() != '/') {
+ tryPath += '/';
+ }
tryPath += name;
if (SystemTools::FileExists(tryPath)) {
return tryPath;
@@ -2720,7 +2841,8 @@ std::string SystemTools::FindFile(const std::string& name,
const std::vector<std::string>& userPaths,
bool no_system_path)
{
- std::string tryPath = SystemTools::FindName(name, userPaths, no_system_path);
+ std::string tryPath =
+ SystemToolsStatic::FindName(name, userPaths, no_system_path);
if (!tryPath.empty() && !SystemTools::FileIsDirectory(tryPath)) {
return SystemTools::CollapseFullPath(tryPath);
}
@@ -2737,7 +2859,8 @@ std::string SystemTools::FindDirectory(
const std::string& name, const std::vector<std::string>& userPaths,
bool no_system_path)
{
- std::string tryPath = SystemTools::FindName(name, userPaths, no_system_path);
+ std::string tryPath =
+ SystemToolsStatic::FindName(name, userPaths, no_system_path);
if (!tryPath.empty() && SystemTools::FileIsDirectory(tryPath)) {
return SystemTools::CollapseFullPath(tryPath);
}
@@ -2773,14 +2896,13 @@ std::string SystemTools::FindProgram(const std::string& name,
// the end of it
// on windows try .com then .exe
if (name.size() <= 3 || name[name.size() - 4] != '.') {
- extensions.push_back(".com");
- extensions.push_back(".exe");
+ extensions.emplace_back(".com");
+ extensions.emplace_back(".exe");
// first try with extensions if the os supports them
- for (std::vector<std::string>::iterator i = extensions.begin();
- i != extensions.end(); ++i) {
+ for (std::string const& ext : extensions) {
tryPath = name;
- tryPath += *i;
+ tryPath += ext;
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
@@ -2799,43 +2921,33 @@ std::string SystemTools::FindProgram(const std::string& name,
SystemTools::GetPath(path);
}
// now add the additional paths
- {
- for (std::vector<std::string>::const_iterator i = userPaths.begin();
- i != userPaths.end(); ++i) {
- path.push_back(*i);
- }
- }
+ path.reserve(path.size() + userPaths.size());
+ path.insert(path.end(), userPaths.begin(), userPaths.end());
// Add a trailing slash to all paths to aid the search process.
- {
- for (std::vector<std::string>::iterator i = path.begin(); i != path.end();
- ++i) {
- std::string& p = *i;
- if (p.empty() || *p.rbegin() != '/') {
- p += "/";
- }
+ for (std::string& p : path) {
+ if (p.empty() || p.back() != '/') {
+ p += '/';
}
}
// Try each path
- for (std::vector<std::string>::iterator p = path.begin(); p != path.end();
- ++p) {
+ for (std::string& p : path) {
#ifdef _WIN32
// Remove double quotes from the path on windows
- SystemTools::ReplaceString(*p, "\"", "");
+ SystemTools::ReplaceString(p, "\"", "");
#endif
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
// first try with extensions
- for (std::vector<std::string>::iterator ext = extensions.begin();
- ext != extensions.end(); ++ext) {
- tryPath = *p;
+ for (std::string const& ext : extensions) {
+ tryPath = p;
tryPath += name;
- tryPath += *ext;
+ tryPath += ext;
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
}
#endif
// now try it without them
- tryPath = *p;
+ tryPath = p;
tryPath += name;
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
@@ -2849,10 +2961,9 @@ std::string SystemTools::FindProgram(const std::vector<std::string>& names,
const std::vector<std::string>& path,
bool noSystemPath)
{
- for (std::vector<std::string>::const_iterator it = names.begin();
- it != names.end(); ++it) {
+ for (std::string const& name : names) {
// Try to find the program.
- std::string result = SystemTools::FindProgram(*it, path, noSystemPath);
+ std::string result = SystemTools::FindProgram(name, path, noSystemPath);
if (!result.empty()) {
return result;
}
@@ -2877,27 +2988,18 @@ std::string SystemTools::FindLibrary(const std::string& name,
std::vector<std::string> path;
SystemTools::GetPath(path);
// now add the additional paths
- {
- for (std::vector<std::string>::const_iterator i = userPaths.begin();
- i != userPaths.end(); ++i) {
- path.push_back(*i);
- }
- }
+ path.reserve(path.size() + userPaths.size());
+ path.insert(path.end(), userPaths.begin(), userPaths.end());
// Add a trailing slash to all paths to aid the search process.
- {
- for (std::vector<std::string>::iterator i = path.begin(); i != path.end();
- ++i) {
- std::string& p = *i;
- if (p.empty() || *p.rbegin() != '/') {
- p += "/";
- }
+ for (std::string& p : path) {
+ if (p.empty() || p.back() != '/') {
+ p += '/';
}
}
std::string tryPath;
- for (std::vector<std::string>::const_iterator p = path.begin();
- p != path.end(); ++p) {
+ for (std::string const& p : path) {
#if defined(__APPLE__)
- tryPath = *p;
+ tryPath = p;
tryPath += name;
tryPath += ".framework";
if (SystemTools::FileIsDirectory(tryPath)) {
@@ -2905,42 +3007,42 @@ std::string SystemTools::FindLibrary(const std::string& name,
}
#endif
#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
- tryPath = *p;
+ tryPath = p;
tryPath += name;
tryPath += ".lib";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
#else
- tryPath = *p;
+ tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".so";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
- tryPath = *p;
+ tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".a";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
- tryPath = *p;
+ tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".sl";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
- tryPath = *p;
+ tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".dylib";
if (SystemTools::FileExists(tryPath, true)) {
return SystemTools::CollapseFullPath(tryPath);
}
- tryPath = *p;
+ tryPath = p;
tryPath += "lib";
tryPath += name;
tryPath += ".dll";
@@ -3202,9 +3304,8 @@ bool SystemTools::FindProgramPath(const char* argv0, std::string& pathOut,
msg << " argv[0] = \"" << argv0 << "\"\n";
}
msg << " Attempted paths:\n";
- std::vector<std::string>::iterator i;
- for (i = failures.begin(); i != failures.end(); ++i) {
- msg << " \"" << *i << "\"\n";
+ for (std::string const& ff : failures) {
+ msg << " \"" << ff << "\"\n";
}
errorMsg = msg.str();
return false;
@@ -3218,6 +3319,7 @@ std::string SystemTools::CollapseFullPath(const std::string& in_relative)
return SystemTools::CollapseFullPath(in_relative, KWSYS_NULLPTR);
}
+#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
void SystemTools::AddTranslationPath(const std::string& a,
const std::string& b)
{
@@ -3234,15 +3336,16 @@ void SystemTools::AddTranslationPath(const std::string& a,
if (SystemTools::FileIsFullPath(path_b) &&
path_b.find("..") == std::string::npos) {
// Before inserting make sure path ends with '/'
- if (!path_a.empty() && *path_a.rbegin() != '/') {
+ if (!path_a.empty() && path_a.back() != '/') {
path_a += '/';
}
- if (!path_b.empty() && *path_b.rbegin() != '/') {
+ if (!path_b.empty() && path_b.back() != '/') {
path_b += '/';
}
if (!(path_a == path_b)) {
- SystemTools::TranslationMap->insert(
- SystemToolsTranslationMap::value_type(path_a, path_b));
+ SystemTools::Statics->TranslationMap.insert(
+ SystemToolsStatic::StringMap::value_type(std::move(path_a),
+ std::move(path_b)));
}
}
}
@@ -3266,22 +3369,21 @@ void SystemTools::CheckTranslationPath(std::string& path)
// Always add a trailing slash before translation. It does not
// matter if this adds an extra slash, but we do not want to
// translate part of a directory (like the foo part of foo-dir).
- path += "/";
+ path += '/';
// In case a file was specified we still have to go through this:
// Now convert any path found in the table back to the one desired:
- std::map<std::string, std::string>::const_iterator it;
- for (it = SystemTools::TranslationMap->begin();
- it != SystemTools::TranslationMap->end(); ++it) {
+ for (auto const& pair : SystemTools::Statics->TranslationMap) {
// We need to check of the path is a substring of the other path
- if (path.find(it->first) == 0) {
- path = path.replace(0, it->first.size(), it->second);
+ if (path.find(pair.first) == 0) {
+ path = path.replace(0, pair.first.size(), pair.second);
}
}
// Remove the trailing slash we added before.
- path.erase(path.end() - 1, path.end());
+ path.pop_back();
}
+#endif
static void SystemToolsAppendComponents(
std::vector<std::string>& out_components,
@@ -3352,6 +3454,7 @@ std::string SystemTools::CollapseFullPath(const std::string& in_path,
// Transform the path back to a string.
std::string newPath = SystemTools::JoinPath(out_components);
+#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
// Update the translation table with this potentially new path. I am not
// sure why this line is here, it seems really questionable, but yet I
// would put good money that if I remove it something will break, basically
@@ -3367,8 +3470,9 @@ std::string SystemTools::CollapseFullPath(const std::string& in_path,
// SystemTools::AddTranslationPath(newPath, in_path);
SystemTools::CheckTranslationPath(newPath);
+#endif
#ifdef _WIN32
- newPath = SystemTools::GetActualCaseForPathCached(newPath);
+ newPath = SystemTools::Statics->GetActualCaseForPathCached(newPath);
SystemTools::ConvertToUnixSlashes(newPath);
#endif
// Return the reconstructed path.
@@ -3428,130 +3532,39 @@ std::string SystemTools::RelativePath(const std::string& local,
// for each entry that is not common in the local path
// add a ../ to the finalpath array, this gets us out of the local
// path into the remote dir
- for (unsigned int i = 0; i < localSplit.size(); ++i) {
- if (!localSplit[i].empty()) {
- finalPath.push_back("../");
+ for (std::string const& lp : localSplit) {
+ if (!lp.empty()) {
+ finalPath.emplace_back("../");
}
}
// for each entry that is not common in the remote path add it
// to the final path.
- for (std::vector<std::string>::iterator vit = remoteSplit.begin();
- vit != remoteSplit.end(); ++vit) {
- if (!vit->empty()) {
- finalPath.push_back(*vit);
+ for (std::string const& rp : remoteSplit) {
+ if (!rp.empty()) {
+ finalPath.push_back(rp);
}
}
std::string relativePath; // result string
// now turn the array of directories into a unix path by puttint /
// between each entry that does not already have one
- for (std::vector<std::string>::iterator vit1 = finalPath.begin();
- vit1 != finalPath.end(); ++vit1) {
- if (!relativePath.empty() && *relativePath.rbegin() != '/') {
- relativePath += "/";
+ for (std::string const& fp : finalPath) {
+ if (!relativePath.empty() && relativePath.back() != '/') {
+ relativePath += '/';
}
- relativePath += *vit1;
+ relativePath += fp;
}
return relativePath;
}
-#ifdef _WIN32
-static std::string GetCasePathName(std::string const& pathIn)
-{
- std::string casePath;
-
- // First check if the file is relative. We don't fix relative paths since the
- // real case depends on the root directory and the given path fragment may
- // have meaning elsewhere in the project.
- if (!SystemTools::FileIsFullPath(pathIn)) {
- // This looks unnecessary, but it allows for the return value optimization
- // since all return paths return the same local variable.
- casePath = pathIn;
- return casePath;
- }
-
- std::vector<std::string> path_components;
- SystemTools::SplitPath(pathIn, path_components);
-
- // Start with root component.
- std::vector<std::string>::size_type idx = 0;
- casePath = path_components[idx++];
- // make sure drive letter is always upper case
- if (casePath.size() > 1 && casePath[1] == ':') {
- casePath[0] = toupper(casePath[0]);
- }
- const char* sep = "";
-
- // If network path, fill casePath with server/share so FindFirstFile
- // will work after that. Maybe someday call other APIs to get
- // actual case of servers and shares.
- if (path_components.size() > 2 && path_components[0] == "//") {
- casePath += path_components[idx++];
- casePath += "/";
- casePath += path_components[idx++];
- sep = "/";
- }
-
- // Convert case of all components that exist.
- bool converting = true;
- for (; idx < path_components.size(); idx++) {
- casePath += sep;
- sep = "/";
-
- if (converting) {
- // If path component contains wildcards, we skip matching
- // because these filenames are not allowed on windows,
- // and we do not want to match a different file.
- if (path_components[idx].find('*') != std::string::npos ||
- path_components[idx].find('?') != std::string::npos) {
- converting = false;
- } 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;
- }
- }
- }
-
- casePath += path_components[idx];
- }
- return casePath;
-}
-#endif
-
std::string SystemTools::GetActualCaseForPath(const std::string& p)
{
-#ifndef _WIN32
- return p;
+#ifdef _WIN32
+ return SystemToolsStatic::GetCasePathName(p);
#else
- return GetCasePathName(p);
+ return p;
#endif
}
-#ifdef _WIN32
-std::string SystemTools::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
- SystemToolsPathCaseMap::iterator i = SystemTools::PathCaseMap->find(p);
- if (i != SystemTools::PathCaseMap->end()) {
- return i->second;
- }
- std::string casePath = GetCasePathName(p);
- if (casePath.size() > MAX_PATH) {
- return casePath;
- }
- (*SystemTools::PathCaseMap)[p] = casePath;
- return casePath;
-}
-#endif
-
const char* SystemTools::SplitPathRootComponent(const std::string& p,
std::string* root)
{
@@ -3648,7 +3661,7 @@ void SystemTools::SplitPath(const std::string& p,
}
#endif
if (!homedir.empty() &&
- (*homedir.rbegin() == '/' || *homedir.rbegin() == '\\')) {
+ (homedir.back() == '/' || homedir.back() == '\\')) {
homedir.resize(homedir.size() - 1);
}
SystemTools::SplitPath(homedir, components);
@@ -3686,8 +3699,7 @@ std::string SystemTools::JoinPath(
// Construct result in a single string.
std::string result;
size_t len = 0;
- std::vector<std::string>::const_iterator i;
- for (i = first; i != last; ++i) {
+ for (std::vector<std::string>::const_iterator i = first; i != last; ++i) {
len += 1 + i->size();
}
result.reserve(len);
@@ -4016,7 +4028,7 @@ bool SystemTools::LocateFileInDir(const char* filename, const char* dir,
filename_dir = SystemTools::GetFilenamePath(filename_dir);
filename_dir_base = SystemTools::GetFilenameName(filename_dir);
#if defined(_WIN32)
- if (filename_dir_base.empty() || *filename_dir_base.rbegin() == ':')
+ if (filename_dir_base.empty() || filename_dir_base.back() == ':')
#else
if (filename_dir_base.empty())
#endif
@@ -4044,16 +4056,16 @@ bool SystemTools::LocateFileInDir(const char* filename, const char* dir,
bool SystemTools::FileIsFullPath(const std::string& in_name)
{
- return SystemTools::FileIsFullPath(in_name.c_str(), in_name.size());
+ return SystemToolsStatic::FileIsFullPath(in_name.c_str(), in_name.size());
}
bool SystemTools::FileIsFullPath(const char* in_name)
{
- return SystemTools::FileIsFullPath(in_name,
- in_name[0] ? (in_name[1] ? 2 : 1) : 0);
+ return SystemToolsStatic::FileIsFullPath(
+ in_name, in_name[0] ? (in_name[1] ? 2 : 1) : 0);
}
-bool SystemTools::FileIsFullPath(const char* in_name, size_t len)
+bool SystemToolsStatic::FileIsFullPath(const char* in_name, size_t len)
{
#if defined(_WIN32) || defined(__CYGWIN__)
// On Windows, the name must be at least two characters long.
@@ -4092,7 +4104,7 @@ bool SystemTools::GetShortPath(const std::string& path, std::string& shortPath)
std::string tempPath = path; // create a buffer
// if the path passed in has quotes around it, first remove the quotes
- if (!path.empty() && path[0] == '"' && *path.rbegin() == '"') {
+ if (!path.empty() && path[0] == '"' && path.back() == '"') {
tempPath = path.substr(1, path.length() - 2);
}
@@ -4169,7 +4181,7 @@ bool SystemTools::GetLineFromStream(std::istream& is, std::string& line,
bool haveData = !line.empty() || !is.eof();
if (!line.empty()) {
// Avoid storing a carriage return character.
- if (*line.rbegin() == '\r') {
+ if (line.back() == '\r') {
line.resize(line.size() - 1);
}
@@ -4307,7 +4319,7 @@ bool SystemTools::IsSubDirectory(const std::string& cSubdir,
if (subdir.size() <= dir.size() || dir.empty()) {
return false;
}
- bool isRootPath = *dir.rbegin() == '/'; // like "/" or "C:/"
+ bool isRootPath = dir.back() == '/'; // like "/" or "C:/"
size_t expectedSlashPosition = isRootPath ? dir.size() - 1u : dir.size();
if (subdir[expectedSlashPosition] != '/') {
return false;
@@ -4354,6 +4366,9 @@ std::string SystemTools::GetOperatingSystemNameAndVersion()
# 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
@@ -4363,7 +4378,11 @@ std::string SystemTools::GetOperatingSystemNameAndVersion()
return 0;
}
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
-# pragma warning(pop)
+# ifdef __clang__
+# pragma clang diagnostic pop
+# else
+# pragma warning(pop)
+# endif
# endif
switch (osvi.dwPlatformId) {
@@ -4651,14 +4670,7 @@ bool SystemTools::ParseURL(const std::string& URL, std::string& protocol,
// These must NOT be initialized. Default initialization to zero is
// necessary.
static unsigned int SystemToolsManagerCount;
-SystemToolsTranslationMap* SystemTools::TranslationMap;
-#ifdef _WIN32
-SystemToolsPathCaseMap* SystemTools::PathCaseMap;
-SystemToolsEnvMap* SystemTools::EnvMap;
-#endif
-#ifdef __CYGWIN__
-SystemToolsTranslationMap* SystemTools::Cyg2Win32Map;
-#endif
+SystemToolsStatic* SystemTools::Statics;
// SystemToolsManager manages the SystemTools singleton.
// SystemToolsManager should be included in any translation unit
@@ -4699,20 +4711,15 @@ void SystemTools::ClassInitialize()
#ifdef __VMS
SetVMSFeature("DECC$FILENAME_UNIX_ONLY", 1);
#endif
- // Allocate the translation map first.
- SystemTools::TranslationMap = new SystemToolsTranslationMap;
-#ifdef _WIN32
- SystemTools::PathCaseMap = new SystemToolsPathCaseMap;
- SystemTools::EnvMap = new SystemToolsEnvMap;
-#endif
-#ifdef __CYGWIN__
- SystemTools::Cyg2Win32Map = new SystemToolsTranslationMap;
-#endif
+ // Create statics singleton instance
+ SystemTools::Statics = new SystemToolsStatic;
+
+#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
// Add some special translation paths for unix. These are not added
// for windows because drive letters need to be maintained. Also,
// there are not sym-links and mount points on windows anyway.
-#if !defined(_WIN32) || defined(__CYGWIN__)
+# if !defined(_WIN32) || defined(__CYGWIN__)
// The tmp path is frequently a logical path so always keep it:
SystemTools::AddKeepPath("/tmp/");
@@ -4750,19 +4757,13 @@ void SystemTools::ClassInitialize()
}
}
}
+# endif
#endif
}
void SystemTools::ClassFinalize()
{
- delete SystemTools::TranslationMap;
-#ifdef _WIN32
- delete SystemTools::PathCaseMap;
- delete SystemTools::EnvMap;
-#endif
-#ifdef __CYGWIN__
- delete SystemTools::Cyg2Win32Map;
-#endif
+ delete SystemTools::Statics;
}
} // namespace KWSYS_NAMESPACE
diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in
index 1967860ab..dd1266bee 100644
--- a/Source/kwsys/SystemTools.hxx.in
+++ b/Source/kwsys/SystemTools.hxx.in
@@ -41,9 +41,7 @@ typedef @KWSYS_NAMESPACE@_VA_LIST::hack_va_list va_list;
namespace @KWSYS_NAMESPACE@ {
-class SystemToolsTranslationMap;
-class SystemToolsPathCaseMap;
-class SystemToolsEnvMap;
+class SystemToolsStatic;
/** \class SystemToolsManager
* \brief Use to make sure SystemTools is initialized before it is used
@@ -54,6 +52,9 @@ class @KWSYS_NAMESPACE@_EXPORT SystemToolsManager
public:
SystemToolsManager();
~SystemToolsManager();
+
+ SystemToolsManager(const SystemToolsManager&) = delete;
+ SystemToolsManager& operator=(const SystemToolsManager&) = delete;
};
// This instance will show up in any translation unit that uses
@@ -890,6 +891,7 @@ public:
*/
static int GetTerminalWidth();
+#if @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP
/**
* Add an entry in the path translation table.
*/
@@ -906,6 +908,7 @@ public:
* Update path by going through the Path Translation table;
*/
static void CheckTranslationPath(std::string& path);
+#endif
/**
* Delay the execution for a specified amount of time specified
@@ -964,41 +967,8 @@ private:
return &SystemToolsManagerInstance;
}
- /**
- * Actual implementation of ReplaceString.
- */
- static void ReplaceString(std::string& source, const char* replace,
- size_t replaceSize, const std::string& with);
-
- /**
- * Actual implementation of FileIsFullPath.
- */
- static bool FileIsFullPath(const char*, size_t);
-
- /**
- * Find a filename (file or directory) in the system PATH, with
- * optional extra paths.
- */
- static std::string FindName(
- const std::string& name,
- const std::vector<std::string>& path = std::vector<std::string>(),
- bool no_system_path = false);
-
- static const char* GetEnvImpl(const char* key);
-
- /**
- * Path translation table from dir to refdir
- * Each time 'dir' will be found it will be replace by 'refdir'
- */
- static SystemToolsTranslationMap* TranslationMap;
-#ifdef _WIN32
- static std::string GetActualCaseForPathCached(std::string const& path);
- static SystemToolsPathCaseMap* PathCaseMap;
- static SystemToolsEnvMap* EnvMap;
-#endif
-#ifdef __CYGWIN__
- static SystemToolsTranslationMap* Cyg2Win32Map;
-#endif
+ static SystemToolsStatic* Statics;
+ friend class SystemToolsStatic;
friend class SystemToolsManager;
};
diff --git a/Source/kwsys/hashtable.hxx.in b/Source/kwsys/hashtable.hxx.in
index fc0d60e7d..0981c66ff 100644
--- a/Source/kwsys/hashtable.hxx.in
+++ b/Source/kwsys/hashtable.hxx.in
@@ -73,7 +73,7 @@ struct _Hashtable_node
void public_method_to_quiet_warning_about_all_methods_private();
private:
- void operator=(_Hashtable_node<_Val> const&); // poison node assignment
+ void operator=(_Hashtable_node<_Val> const&) = delete;
};
template <class _Val, class _Key, class _HashFcn, class _ExtractKey,
diff --git a/Source/kwsys/kwsysPlatformTestsCXX.cxx b/Source/kwsys/kwsysPlatformTestsCXX.cxx
index b77d7292a..cfd5666f3 100644
--- a/Source/kwsys/kwsysPlatformTestsCXX.cxx
+++ b/Source/kwsys/kwsysPlatformTestsCXX.cxx
@@ -136,42 +136,6 @@ int main()
}
#endif
-#ifdef TEST_KWSYS_LFS_WORKS
-/* Return 0 when LFS is available and 1 otherwise. */
-# define _LARGEFILE_SOURCE
-# define _LARGEFILE64_SOURCE
-# define _LARGE_FILES
-# define _FILE_OFFSET_BITS 64
-# include <sys/types.h>
-
-# include <assert.h>
-# include <sys/stat.h>
-# if KWSYS_CXX_HAS_CSTDIO
-# include <cstdio>
-# endif
-# include <stdio.h>
-
-int main(int, char** argv)
-{
-/* check that off_t can hold 2^63 - 1 and perform basic operations... */
-# define OFF_T_64 (((off_t)1 << 62) - 1 + ((off_t)1 << 62))
- if (OFF_T_64 % 2147483647 != 1)
- return 1;
-
- // stat breaks on SCO OpenServer
- struct stat buf;
- stat(argv[0], &buf);
- if (!S_ISREG(buf.st_mode))
- return 2;
-
- FILE* file = fopen(argv[0], "r");
- off_t offset = ftello(file);
- fseek(file, offset, SEEK_CUR);
- fclose(file);
- return 0;
-}
-#endif
-
#ifdef TEST_KWSYS_CXX_HAS_SETENV
# include <stdlib.h>
int main()
@@ -212,12 +176,6 @@ int main()
#endif
#ifdef TEST_KWSYS_CXX_HAS_RLIMIT64
-# if defined(KWSYS_HAS_LFS)
-# define _LARGEFILE_SOURCE
-# define _LARGEFILE64_SOURCE
-# define _LARGE_FILES
-# define _FILE_OFFSET_BITS 64
-# endif
# include <sys/resource.h>
int main()
{
diff --git a/Source/kwsys/testConsoleBuf.cxx b/Source/kwsys/testConsoleBuf.cxx
index 154944058..b6ad1188d 100644
--- a/Source/kwsys/testConsoleBuf.cxx
+++ b/Source/kwsys/testConsoleBuf.cxx
@@ -499,6 +499,9 @@ static int testConsole()
# 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
@@ -506,7 +509,11 @@ static int testConsole()
const bool isVistaOrGreater =
LOBYTE(LOWORD(GetVersion())) >= HIBYTE(_WIN32_WINNT_VISTA);
# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion
-# pragma warning(pop)
+# ifdef __clang__
+# pragma clang diagnostic pop
+# else
+# pragma warning(pop)
+# endif
# endif
if (!isVistaOrGreater) {
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_READ | KEY_WRITE,
diff --git a/Source/kwsys/testDynamicLoader.cxx b/Source/kwsys/testDynamicLoader.cxx
index ce87117a1..eff2ed7ee 100644
--- a/Source/kwsys/testDynamicLoader.cxx
+++ b/Source/kwsys/testDynamicLoader.cxx
@@ -21,11 +21,15 @@
// left on disk.
#include <testSystemTools.h>
-static std::string GetLibName(const char* lname)
+static std::string GetLibName(const char* lname, const char* subdir = NULL)
{
// Construct proper name of lib
std::string slname;
slname = EXECUTABLE_OUTPUT_PATH;
+ if (subdir) {
+ slname += "/";
+ slname += subdir;
+ }
#ifdef CMAKE_INTDIR
slname += "/";
slname += CMAKE_INTDIR;
@@ -45,26 +49,29 @@ static std::string GetLibName(const char* lname)
* r3: should CloseLibrary succeed ?
*/
static int TestDynamicLoader(const char* libname, const char* symbol, int r1,
- int r2, int r3)
+ int r2, int r3, int flags = 0)
{
std::cerr << "Testing: " << libname << std::endl;
kwsys::DynamicLoader::LibraryHandle l =
- kwsys::DynamicLoader::OpenLibrary(libname);
+ kwsys::DynamicLoader::OpenLibrary(libname, flags);
// If result is incompatible with expectation just fails (xor):
if ((r1 && !l) || (!r1 && l)) {
- std::cerr << kwsys::DynamicLoader::LastError() << std::endl;
+ std::cerr << "OpenLibrary: " << kwsys::DynamicLoader::LastError()
+ << std::endl;
return 1;
}
kwsys::DynamicLoader::SymbolPointer f =
kwsys::DynamicLoader::GetSymbolAddress(l, symbol);
if ((r2 && !f) || (!r2 && f)) {
- std::cerr << kwsys::DynamicLoader::LastError() << std::endl;
+ std::cerr << "GetSymbolAddress: " << kwsys::DynamicLoader::LastError()
+ << std::endl;
return 1;
}
#ifndef __APPLE__
int s = kwsys::DynamicLoader::CloseLibrary(l);
if ((r3 && !s) || (!r3 && s)) {
- std::cerr << kwsys::DynamicLoader::LastError() << std::endl;
+ std::cerr << "CloseLibrary: " << kwsys::DynamicLoader::LastError()
+ << std::endl;
return 1;
}
#else
@@ -113,5 +120,14 @@ int testDynamicLoader(int argc, char* argv[])
res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderData", 1, 1, 1);
res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderData", 1, 0, 1);
+#ifdef _WIN32
+ libname = GetLibName(KWSYS_NAMESPACE_STRING "TestDynloadUse", "dynloaddir");
+ res += TestDynamicLoader(libname.c_str(), "dummy", 0, 0, 0);
+ res += TestDynamicLoader(libname.c_str(), "TestLoad", 1, 1, 1,
+ kwsys::DynamicLoader::SearchBesideLibrary);
+ res += TestDynamicLoader(libname.c_str(), "_TestLoad", 1, 0, 1,
+ kwsys::DynamicLoader::SearchBesideLibrary);
+#endif
+
return res;
}
diff --git a/Source/kwsys/testDynloadImpl.c b/Source/kwsys/testDynloadImpl.c
new file mode 100644
index 000000000..2b9069bc7
--- /dev/null
+++ b/Source/kwsys/testDynloadImpl.c
@@ -0,0 +1,10 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
+
+#include "testDynloadImpl.h"
+
+int TestDynamicLoaderImplData = 0;
+
+void TestDynamicLoaderImplSymbolPointer()
+{
+}
diff --git a/Source/kwsys/testDynloadImpl.h b/Source/kwsys/testDynloadImpl.h
new file mode 100644
index 000000000..d0c9dfb75
--- /dev/null
+++ b/Source/kwsys/testDynloadImpl.h
@@ -0,0 +1,15 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
+#ifdef _WIN32
+# ifdef BUILDING_TestDynloadImpl
+# define DLIMPL_EXPORT __declspec(dllexport)
+# else
+# define DLIMPL_EXPORT __declspec(dllimport)
+# endif
+#else
+# define DLIMPL_EXPORT
+#endif
+
+DLIMPL_EXPORT int TestDynamicLoaderImplData;
+
+DLIMPL_EXPORT void TestDynamicLoaderImplSymbolPointer();
diff --git a/Source/kwsys/testDynloadUse.c b/Source/kwsys/testDynloadUse.c
new file mode 100644
index 000000000..5402add6a
--- /dev/null
+++ b/Source/kwsys/testDynloadUse.c
@@ -0,0 +1,15 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
+#include "testDynloadImpl.h"
+
+#ifdef _WIN32
+# define DL_EXPORT __declspec(dllexport)
+#else
+# define DL_EXPORT
+#endif
+
+DL_EXPORT int TestLoad()
+{
+ TestDynamicLoaderImplSymbolPointer();
+ return TestDynamicLoaderImplData;
+}